@playstack/auth-react
React session state, client auth actions, revalidation, and cross-tab synchronization.
Free. MIT licensed. Check preview availability before installing. See package access.
@playstack/auth-react provides headless session state, client actions, revalidation, and cross-tab synchronization around a server-owned @playstack/auth session.
Install and compose
npm install @playstack/auth @playstack/auth-react reactimport {
PlaystackAuthProvider,
createFetchAuthTransport,
} from '@playstack/auth-react'
const transport = createFetchAuthTransport({
baseUrl: 'https://api.example.com',
headers: () => ({ 'x-csrf-token': readCsrfCookie() }),
})
<PlaystackAuthProvider transport={transport} initialSession={initialSession}>
<App />
</PlaystackAuthProvider>Omit initialSession to fetch on mount, pass null when SSR proved the request unauthenticated, or pass a validated session to render authenticated immediately.
Provider properties
| Property | Default | Purpose |
|---|---|---|
transport | Required | Server communication bridge. |
initialSession | undefined | Initial safe projection; controls the first loading state. |
revalidateOnFocus | true | Refresh state when the window regains focus. |
refreshBeforeMs | 60000 | Refresh this long before session expiry. |
sync | Browser sync | Custom AuthSync, default cross-tab sync, or false. |
onError | None | Isolated error observer. |
useSession() returns status, session, user, error, and revalidate. useAuth() returns signIn, signOut, refresh, and replaceSession. refresh re-establishes the session through the transport's refresh path and applies the result; call it after the server rotated the credential, such as an account switch with the bearer transport. Every replacement is validated against AuthSessionView.
Transport bridge
interface AuthTransport {
client: unknown
getSession(): Promise<AuthSessionView | null>
refresh(): Promise<AuthSessionView | null>
signIn(input?: unknown): Promise<AuthSessionView>
signOut(): Promise<void>
}The included fetch transport defaults to GET /api/auth/session and POST /api/auth/refresh, /api/auth/sign-in, and /api/auth/sign-out, always including cookies. Configure fetch, baseUrl, any endpoint path, and a sync/async headers callback. A session 401 receives exactly one refresh attempt.
Split-origin browser applications
Use the bearer profile when the browser application and API are hosted on different origins:
import { createBearerAuthTransport } from '@playstack/auth-react'
const transport = createBearerAuthTransport({
baseUrl: 'https://api.example.com',
})The API keeps the rotating refresh credential in a secure HTTP-only cookie and
returns exactly { session, accessToken, accessExpiresAt } from sign-in and
refresh. The short-lived opaque access token stays in transport memory and is
sent as a bearer credential. A reload bootstraps a new access token through the
refresh cookie; responses that expose a refresh token or unknown credential
fields fail closed.
A cross-origin page cannot read a CSRF cookie set on the API origin, so there
is no synchronizer header in this profile. The API protects its cookie-bearing
routes with Origin and Sec-Fetch-Site checks (PlaystackOriginGuard in
@playstack/nest-auth) and enables CORS with credentials for the
application's origins only; the application still owns those allowlists, the
routes, and the cookie attributes. Those checks apply to browser requests
only: a client that sends no Origin, no Fetch Metadata and no cookie has
no ambient credential, so a CLI, a mobile app or a server can reach the same
routes with its bearer token, and the API may hand such a client the whole
token pair in the body instead of a cookie. baseUrl must be
HTTPS except for loopback hosts, which browsers treat as secure contexts, so
local development can point at http://127.0.0.1:<port> without a TLS proxy.
An account switch that issues a new session on the server also rotates the
refresh cookie. Pass refresh from useAuth() as the accounts provider's
onSessionChange so the transport adopts the cookie and obtains the access
token for the new session:
const { session } = useSession()
const { refresh } = useAuth()
<PlaystackAccountsProvider client={accounts} session={session} onSessionChange={refresh}>
{children}
</PlaystackAccountsProvider>Sync and token-storage bridges
AuthSync exposes publish, subscribe, and close plus its native client. The browser implementation uses BroadcastChannel with a storage-event fallback.
TokenStorage exposes get, set, and clear plus its native client for non-cookie applications. createExpoTokenStorage(SecureStore, { key? }) stores only opaque tokens and numeric expiries and rejects expanded or malformed records.
Guards and boundary
RequireSession accepts loadingFallback, unauthenticated fallback, and children. It is navigation UX only—not a server security or account authorization boundary. React and all Playstack peers remain application-controlled at the same fixed version.
API entry points and requirements
Reference snapshot: @playstack/auth-react@0.1.0-beta.1. Import only the entry point your runtime needs. Paths below are relative to the installed package; use Go to Definition in your editor to inspect exact parameters, return types and overloads. Do not import the declaration-file paths directly.
| Public entry point | Declaration file |
|---|---|
@playstack/auth-react | ./dist/index.d.ts |
@playstack/auth-react/errors | ./dist/errors.d.ts |
@playstack/auth-react/expo | ./dist/expo.d.ts |
@playstack/auth-react/package.json | No TypeScript declaration (asset or metadata export). |
Node.js engine requirement: >=20. This is not a claim that every entry point works in browsers or Workers.
Peer dependencies
Keep existing framework versions that satisfy these ranges. Install optional peers only when using the corresponding adapter. The package manager resolves ordinary dependencies separately.
| Peer | Compatible range | When needed |
|---|---|---|
@playstack/auth-contracts | 0.1.0-beta.1 | Required by the package. |
@playstack/core | 0.1.0-beta.1 | Required by the package. |
react | ^18.2.0 || ^19.0.0 | Required by the package. |
For a complete first program, start with Getting started. For API lookup and partial-example conventions, see Reading the reference. Provider failures, lifecycle requirements and application responsibilities remain described in the guide above; types alone do not establish production safety.