<ToriiProvider>
<ToriiProvider> wraps your app, owns session state, refreshes the access
token in the background, and exposes everything to the tree via React context.
Every Torii component and hook (<SignIn>, <UserButton>, useAuth(), etc.)
must render inside it.
Session management uses HttpOnly cookies, so the session token is never exposed to JavaScript. Only the short-lived JWT is held in memory and re-minted from the cookie on page load.
import { ToriiProvider } from '@torii-js/torii-react';
createRoot(document.getElementById('root')!).render( <ToriiProvider publishableKey={import.meta.env.VITE_TORII_PUBLISHABLE_KEY}> <App /> </ToriiProvider>,);The publishable key is the only required prop. Everything else is opt-in.
| Name | Type | Default | Description |
|---|---|---|---|
publishableKey | string | - | Required. Publishable key (pk_live_… or pk_test_…) issued for your environment. The SDK decodes its API origin from this key. |
children | ReactNode | - | Required. Your application tree. |
proxyOrigin | string | - | Absolute origin (e.g. "https://auth.example.com") to route SDK requests through, for first-party session cookies. Required unless your environment uses a verified CNAME custom domain; without one, cookies are third-party and blocked by Safari. Must be http/https; throws synchronously at mount otherwise. See first-party cookies. |
navigate | (path: string) => void | full-page redirect | SPA-router navigation callback. When set, every internal SDK redirect (<RedirectToSignIn>, <RedirectToGates>, post-OAuth landing) calls this instead of setting window.location.href, preserving router state. OAuth provider start (bouncing to the IdP) always does a real navigation regardless. |
appearance | AppearanceConfig | { theme: 'shadcn' } | Visual config: a theme preset ('shadcn' | 'mui') or full Theme, token variables, and per-slot elements. See theming. |
languages | LanguageInput[] | ['da', 'en'] | Available languages. Each entry is a built-in code ('en' | 'da') or a full LanguageConfig. The SDK always auto-detects the browser locale against the configured (or default ['da', 'en']) languages, renders the language picker, and exposes it via useAuth().setLanguage. Pass ['en'] to ship English-only. Unknown bare codes throw at mount. See labels & i18n. |
cdnUrl | string | https://cdn.torii.so/sdk/v0/latest/runtime.js | Override the origin the signed UI runtime (runtime.js) is fetched from. Defaults to the baked-in production runtime origin. Point it at a self-hosted mirror for a strict CSP, an air-gapped deployment, or a native WebView. Must be an absolute http(s) URL; validated at mount (throws synchronously if malformed). |
manifestUrl | string | https://manifest.torii.so/manifest.json | Override the origin the signed integrity manifest (manifest.json) is fetched from. Defaults to the baked-in production manifest origin. Set it alongside cdnUrl when serving from a self-hosted mirror (the manifest’s hashes must match the runtime served). Must be an absolute http(s) URL; validated at mount (throws synchronously if malformed). |
events | ToriiProviderEvents | - | Session-lifecycle telemetry hooks. All optional. See Events. |
afterOauthSignInPath | string | "/" | Where the server sends the browser after an OAuth sign-in callback. OAuth-only: password sign-in is in-page (flip render gates or route via onLoginSuccess). |
afterOauthSignUpPath | string | afterOauthSignInPath | Where the server lands the browser after an OAuth sign-up callback. Inherits afterOauthSignInPath, so setting only that covers both. |
afterOauthLinkPath | string | "/" | Where the server lands the browser after an OAuth identity-link callback. Set this when <ConnectedAccounts> lives on a non-root route. |
gateUrls | Partial<Record<GateKey, string>> | {} | Per-gate-key URL map consumed by <RedirectToGates> to route a user with a pending session gate. See session gates. |
isSatellite | boolean | false | Marks this app as a satellite, served from a different registrable domain than your primary, sharing the primary’s session. Requires domain. See Satellite domains. |
domain | string | - | Required for a satellite. The satellite’s own domain (e.g. "app.acme.io" or a full origin); it can’t be derived from the publishable key, which encodes your primary. This is the host the satellite’s session cookie is set on. Must resolve to http/https. |
satelliteAutoSync | boolean | true | Whether a satellite automatically syncs with the primary on initial load when it has no local session. Set false to trigger the sync yourself. |
signInUrl | string | - | URL of your sign-in page. For a satellite this must point to your primary: sign-in is hosted there, not on satellites. Exposed on the auth context. |
signUpUrl | string | - | URL of your sign-up page. For a satellite this must point to your primary: sign-up is hosted there, not on satellites. Exposed on the auth context. |
Satellite domains (multi-domain SSO)
Section titled “Satellite domains (multi-domain SSO)”A satellite is an app on a different registrable domain than your primary
(e.g. acme.com and acme.io) that shares the same session. Because a cookie
can’t span different registrable domains, a satellite syncs the session from the
primary via a redirect handshake.
Set the primary’s publishable key on every app (the key encodes the primary
FAPI). On the satellite, also set isSatellite, its own domain, and the
primary’s signInUrl / signUpUrl:
// On the primary (acme.com), nothing extra needed.<ToriiProvider publishableKey="pk_live_…">{children}</ToriiProvider>
// On a satellite (acme.io)<ToriiProvider publishableKey="pk_live_…" // the PRIMARY's key isSatellite domain="acme.io" // the satellite's own domain signInUrl="https://acme.com/sign-in" // sign-in lives on the primary> {children}</ToriiProvider>On a cold load with no local session, the satellite bounces to the primary to
sync one (unless satelliteAutoSync={false}); if the primary has no session
either, it returns and renders signed-out. Each satellite domain must be
registered and verified for the environment in the dashboard.
Native (Capacitor) props
Section titled “Native (Capacitor) props”For a Capacitor / hybrid-native app, two more props switch the SDK into a cookie-less mode (session token in secure storage, system-browser OAuth). They have no effect in a normal web build. See Native (Capacitor) auth for the full setup.
| Name | Type | Description |
|---|---|---|
tokenCache | ToriiTokenCache | Secure-storage adapter ({ getToken, saveToken, clearToken }). Supplying it turns on cookie-less native mode. |
nativeOAuth | { browser: { openOAuth: (url) => Promise<string | null> }; redirect: string } | Native OAuth config: the system-browser bridge plus its deep-link target (which must be in the environment’s allowed native redirects). Required for native OAuth. |
Navigation: OAuth vs. password
Section titled “Navigation: OAuth vs. password”The three afterOauth* paths drive OAuth callback landing only: OAuth
can’t resolve in-page, so the server redirects the browser to a configured
path. Password sign-in/up never navigate: they flip session state in-place,
so <SignedIn> / <SignedOut> swap immediately. Route password flows
explicitly from onLoginSuccess / onSignupSuccess, preferring your router
over window.location.href so query/hash state survives.
Events
Section titled “Events”The events prop is a bag of optional session-lifecycle callbacks, pure
telemetry. They are not navigation hooks: OAuth landing is owned by the
afterOauth* paths, and password flows route via the per-form
onLoginSuccess / onSignupSuccess.
| Field | Signature | Fired when |
|---|---|---|
onSessionExpired | () => void | The session ends server-side (expired or revoked). |
onError | (error: ToriiError) => void | A non-fatal SDK error, such as a failed token refresh or a failed server-side sign-out. Read error.code (a stable, machine-branchable code) and error.message. Telemetry only; the SDK still settles to a coherent state (signed-out on expiry; local sign-out proceeds regardless). |
<ToriiProvider publishableKey="pk_live_…" events={{ onSessionExpired: () => router.navigate({ to: '/sign-in', search: { expired: true } }), onError: (err) => reportError(err), }}> <App /></ToriiProvider>When a callback is unwired, the corresponding event is silent (no SDK-level log): telemetry is strictly opt-in.
The auth context
Section titled “The auth context”The provider feeds everything to the tree through React context. Read it with
the useAuth() hook, which returns the curated public
AuthContextValue:
- State:
isLoaded,isLoading,isSignedIn,user,userProfile,organizations,currentLanguage,runtimeIncompatible. - Actions:
require(role/permission authorization check),getToken(async, refreshes first if the current token is near expiry),getAccessToken(synchronous, no refresh),signIn,signOut,refreshSession,setLanguage.
useAuth().organizations is the user’s membership list; use
useOrganizations() to switch the active org
or manage members.
The provider’s context carries additional fields the SDK’s own components read
internally; those are deliberately not part of the public useAuth() type.
import { useAuth } from '@torii-js/torii-react';
function Greeting() { const { isLoaded, isSignedIn, user } = useAuth(); if (!isLoaded) return <Spinner />; if (!isSignedIn) return null; return <span>Hi, {user?.id}</span>;}Behaviour notes
Section titled “Behaviour notes”- Runtime loading. UI and auth logic load from the CDN at first render.
Until the runtime resolves the provider reports
isLoading: true; on a hard load failure it settles signed-out and surfaces the failure via<ToriiFailed>/useRuntimeStatus(). For a strict CSP, allowscript-src cdn.torii.soandconnect-src manifest.torii.so. To self-host or air-gap, pointcdnUrl/manifestUrlat your own mirror and allow those origins instead. - Cross-tab sync. Sign-in / sign-out broadcast to other tabs of the same origin (no token crosses the channel; the receiving tab re-mints from its own cookie).
- Background refresh. The JWT is refreshed automatically (and on tab
refocus). A failed refresh falls through to
events.onSessionExpired.
TypeScript
Section titled “TypeScript”import type { ToriiProviderProps, ToriiProviderEvents, AuthContextValue,} from '@torii-js/torii-react';