Control Components
Control components render their children based on the auth
lifecycle. They don’t draw a surface of their own; each returns
null (or a fallback) until its condition is met. They make it trivial
to show different UI for signed-in and signed-out users.
All control components must be rendered inside <ToriiProvider>.
For gating on the runtime load lifecycle (the CDN/bundled UI bundle + its styles) rather than auth state, see runtime status.
Overview
Section titled “Overview”| Component | Renders children when… |
|---|---|
<SignedIn> | Signed in and the session has no pending gates. |
<SignedOut> | Signed out (or a session gate is pending). |
<AuthLoading> | The initial session probe is still in flight. |
<Show> | Signed in, and (if when is given) the user has a matching role/permission. |
<RedirectToSignIn> | Signed out; navigates to your sign-in page. |
<RedirectToGates> | A session gate is pending; routes to its configured URL. |
SignedIn
Section titled “SignedIn”Renders its children only when the user is signed in and the session
has cleared every authentication-critical gate (status === 'active').
A pending session (session.status === 'pending') renders as
null, so protected UI never appears while a
session gate is outstanding. A session is pending
whenever an authentication gate has yet to clear: the user’s email is
not yet verified, or legal consent has not been given (for example the
legal-consent step during OAuth sign-up). While that gate is
outstanding <SignedIn> (and <Show>) render nothing, and
<SignedOut> renders its children so the gate-completion
UI can show. Drive gate completion with gateUrls on <ToriiProvider>,
render <RedirectToGates>, or read
useSession().session.currentGate yourself.
import { SignedIn, UserButton } from '@torii-js/torii-react';
function Header() { return ( <header> <Logo /> <SignedIn> <UserButton /> </SignedIn> </header> );}| Name | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Rendered when signed in with no pending gate. |
SignedOut
Section titled “SignedOut”Renders its children when the user is signed out or has a pending
session gate. Pending counts as “not signed in for rendering purposes”,
so your signed-out shell (typically hosting <SignIn> / <SignUp>) can
also host the gate-completion UI.
import { SignedOut, SignIn } from '@torii-js/torii-react';
function Header() { return ( <SignedOut> <SignIn /> </SignedOut> );}| Name | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Rendered when signed out or a gate is pending. |
Combining SignedIn and SignedOut
Section titled “Combining SignedIn and SignedOut”Use both together to swap content based on auth state:
import { ToriiProvider, SignedIn, SignedOut } from '@torii-js/torii-react';
function App() { return ( <ToriiProvider publishableKey="pk_live_your-key"> <SignedIn> <Dashboard /> </SignedIn> <SignedOut> <SignIn /> </SignedOut> </ToriiProvider> );}AuthLoading
Section titled “AuthLoading”Renders its children while the authentication state is being determined
(useAuth().isLoading), e.g. while checking for an existing session
cookie on page load. Use it to paint a skeleton before the gates decide.
import { AuthLoading, SignedIn, SignedOut } from '@torii-js/torii-react';
function App() { return ( <ToriiProvider publishableKey="pk_live_your-key"> <AuthLoading> <FullPageSpinner /> </AuthLoading> <SignedIn> <Dashboard /> </SignedIn> <SignedOut> <SignIn /> </SignedOut> </ToriiProvider> );}| Name | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Rendered while the initial session probe is in flight. |
Render gate: renders children when the user is signed in and
(if a when prop is given) satisfies the role/permission check; else
renders fallback (or nothing). It also fires onUnauthorized in an
effect once the session probe resolves and the check fails.
Like <SignedIn>, it excludes pending sessions; those
count as not signed in for rendering.
This is a signed-in gate with optional role/permission authorization.
Authorize with the when
prop, or imperatively with useAuth().require({ role | permission }).
System permissions (
org:sys_*) are not tokenized, so check them via{ role }. The{ permission }form is reserved for future custom permissions.
| Name | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Rendered when signed in and the when check (if any) passes. |
when | AuthorizationParams | - | Optional role/permission requirement: { role: string } or { permission: string } (prefixed keys, e.g. { role: 'org:admin' }). |
fallback | ReactNode | - | Rendered instead of children when the check fails. Can be combined with onUnauthorized. |
onUnauthorized | () => void | - | Fired in an effect once the session is loaded and the check fails. Can be combined with fallback. |
With fallback
Section titled “With fallback”import { Show } from '@torii-js/torii-react';
function ProtectedPage() { return ( <Show fallback={<LoginPrompt />}> <SecretContent /> </Show> );}Gating on a role
Section titled “Gating on a role”import { Show } from '@torii-js/torii-react';
function AdminPanel() { return ( <Show when={{ role: 'org:admin' }} fallback={<NotAllowed />}> <DangerousSettings /> </Show> );}With redirect
Section titled “With redirect”import { Show, RedirectToSignIn } from '@torii-js/torii-react';
function ProtectedPage() { return ( <Show fallback={<RedirectToSignIn signInUrl="/sign-in" />}> <Dashboard /> </Show> );}Authorizing imperatively
Section titled “Authorizing imperatively”For logic outside a render gate, use useAuth().require(...), a
role/permission authorization check. It returns a boolean:
import { useAuth } from '@torii-js/torii-react';
function Toolbar() { const { require } = useAuth(); return ( <> {require({ role: 'org:admin' }) && <DeleteButton />} </> );}RedirectToSignIn
Section titled “RedirectToSignIn”Navigates the user to your sign-in page when they’re signed out. Waits
for the initial session probe before firing, so already-signed-in users
aren’t bounced. Honors ToriiProvider.navigate when set; otherwise does
a full-page redirect. Renders null.
| Name | Type | Default | Description |
|---|---|---|---|
signInUrl | string | - | Required. Path to your sign-in page (e.g. "/sign-in"). |
returnUrl | string | Current path + search | Value for the appended returnUrl query param. |
import { SignedOut, SignedIn, RedirectToSignIn } from '@torii-js/torii-react';
function ProtectedPage() { return ( <> <SignedOut> <RedirectToSignIn signInUrl="/sign-in" /> </SignedOut> <SignedIn> <Dashboard /> </SignedIn> </> );}The current path is appended as returnUrl so you can route the user
back after sign-in. Override it with the returnUrl prop:
<RedirectToSignIn signInUrl="/sign-in" returnUrl="/checkout" />RedirectToGates
Section titled “RedirectToGates”Routes a user with a pending session gate to the URL registered in
<ToriiProvider gateUrls={…}>. Honors ToriiProvider.navigate when set;
otherwise does a full-page redirect. Renders null.
When the current gate has no gateUrls entry it is a no-op but logs a
one-shot console warning, so a misconfigured mapping surfaces in dev
before it strands a user.
Don’t mount alongside
<RedirectToSignIn>. Both fire navigation effects on the same render; if both qualify at once the destination is undefined. Render exactly one, gated on your own routing condition.
<RedirectToGates> takes no props.
import { SignedOut, RedirectToGates, SignIn } from '@torii-js/torii-react';
function AuthPage() { return ( <SignedOut> <RedirectToGates /> <SignIn /> </SignedOut> );}Reading the user
Section titled “Reading the user”For the signed-in user’s identity, use the
useUser hook, or the full profile via
useAuth().userProfile.
Server-side rendering
Section titled “Server-side rendering”<ToriiProvider> resolves the session client-side from a cookie, so
there’s no server-rendered auth state. During SSR (and the pre-probe
first paint) the gates read the SSR-safe optimisticSignedIn snapshot,
which is false on the server. So server-side <SignedIn>, <Show>,
<RedirectToSignIn>, and <RedirectToGates> render nothing, but
<SignedOut> renders its children and <AuthLoading> renders its
children (because isLoading is true until the probe settles). On the
client, before the probe settles, <SignedIn> / <SignedOut> paint
from the session-hint cookie.
For a smoother first paint, wrap the signed-in surface in
<AuthLoading> and render a skeleton while the cookie probe is in
flight:
<AuthLoading> <DashboardSkeleton /></AuthLoading><SignedIn> <Dashboard /></SignedIn><SignedOut> <RedirectToSignIn signInUrl="/sign-in" /></SignedOut>TypeScript
Section titled “TypeScript”import type { ControlComponentProps, ShowProps, RedirectToSignInProps,} from '@torii-js/torii-react';