framework
React
Headless domain bindings plus optional Chakra application and admin compositions, with server authority kept outside the client.
Authenticate browser extensions, CLIs, desktop apps, and mobile clients through system-browser authorization, PKCE, rotation, and device-aware revocation.
available
Reuse the product's web authentication, MFA, SSO, and consent screens without embedding credentials in a public client.
available
Complete authorization through extension redirects, mobile sessions, or verified loopback listeners with explicit state handling.
Packages
preview
S256-bound device grants, explicit consent, bounded polling and transactional one-time issuance.
Frameworks and integrations
available
Store credentials in platform-appropriate boundaries, rotate refresh families, and connect every client session to a revocable device.
framework
Headless domain bindings plus optional Chakra application and admin compositions, with server authority kept outside the client.
framework
Compose Playstack server contracts, React bindings, SSR handoff, and route adapters at the Next.js application edge.
framework
Connect portable Playstack capabilities to dependency injection, guards, decorators, request context, workers, and lifecycle hooks.
Extension bundles, desktop binaries, mobile applications, and installed CLIs are inspectable. Client authentication therefore uses authorization code with PKCE rather than pretending a bundled client secret is confidential.
The client opens the product's own authorization page in the system browser. Existing sessions, passkeys, MFA, SSO, and consent remain web application responsibilities.
import {
createClientAuth,
createFetchTokenTransport,
} from '@playstack/client-auth'
const auth = createClientAuth({
clientId: 'desktop-app',
authorizationEndpoint: 'https://app.example.com/oauth/authorize',
redirectUri,
scopes: ['profile', 'devices'],
transport: createFetchTokenTransport({
tokenEndpoint: 'https://api.example.com/oauth/token',
revocationEndpoint: 'https://api.example.com/oauth/revoke',
}),
storage: platformCredentialStorage,
launcher: systemBrowserLauncher,
})
await auth.authorize()
const response = await auth.request(request, apiTransport)
await auth.signOut()Browser extensions replace the launcher and callback with launchWebAuthFlow; mobile uses the platform authentication session; a CLI can fall back to the device authorization flow when a loopback callback is unavailable.
Client authentication establishes a session between one client and the application API. Device pairing establishes mutual trust between two peers. A desktop companion and extension may need both, and the contracts compose without sharing secrets or pretending they solve the same problem.
The authorization-server additions belong to @playstack/auth and @playstack/nest-auth. @playstack/client-auth owns launch, callback, exchange, storage, refresh, authenticated-request retry, and revocation on the installed client. Its Node-only loopback entrypoint binds an ephemeral 127.0.0.1 callback, accepts one response, and closes. Device authorization now ships through @playstack/auth/device, @playstack/client-auth/device and Nest integration. Successful exchange is one-time: a lost committed token response requires a new authorization flow, not recovery of the same secret.