Components
Full prop reference for <SignIn>, <SignUp>, <UserButton>,
<UserDashboard>, and <UserProfile>.
Browse →
Add Torii authentication to a React app. This guide uses Vite; the same steps work for any React framework; only the environment-variable plumbing changes.
Sign up at app.torii.so and click New application.
Name it after your app. From Settings → API keys, copy the publishable
key; it looks like pk_test_… in sandbox and pk_live_… in production.
Under Settings → Allowed origins, add http://localhost:5173 (or whatever
port your dev server uses). Without this the API rejects browser requests
with a CORS error.
@torii-js/torii-reactbun add @torii-js/torii-reactnpm install @torii-js/torii-reactpnpm add @torii-js/torii-reactyarn add @torii-js/torii-reactCreate or open .env.local at the project root and add your publishable key:
VITE_TORII_PUBLISHABLE_KEY=pk_test_your-publishable-keyVite exposes any variable prefixed with VITE_ to client code. Other
frameworks have similar conventions: NEXT_PUBLIC_… for Next.js,
PUBLIC_… for Astro, etc.
<ToriiProvider> to your appWrap your root with <ToriiProvider> and pass the publishable key. The
provider owns session state, refreshes JWTs in the background, and
exposes the useAuth() hook to the rest of the tree.
import { ToriiProvider } from '@torii-js/torii-react';import { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import App from './App';
const PUBLISHABLE_KEY = import.meta.env.VITE_TORII_PUBLISHABLE_KEY;
if (!PUBLISHABLE_KEY) { throw new Error('Missing VITE_TORII_PUBLISHABLE_KEY');}
createRoot(document.getElementById('root')!).render( <StrictMode> <ToriiProvider publishableKey={PUBLISHABLE_KEY}> <App /> </ToriiProvider> </StrictMode>,);<AuthLoading>, <SignedOut>, and <SignedIn> are control components;
each renders its children for exactly one phase of the auth lifecycle.
On every page load the provider runs a session probe (the cookie is
checked against the server); these three tags cover all three outcomes:
<AuthLoading>: the probe is still in flight. Render a spinner or
skeleton. Skipping it means signed-in users briefly see the sign-in
card flash on reload before the probe resolves.<SignedOut>: no session. Render <SignIn> (the prebuilt card).<SignedIn>: authenticated. Render <UserDashboard>, the full
account surface. It bundles the <UserButton> avatar menu, an
email-verification banner, and the profile panel: editable profile
fields, connected accounts (account linking), active sessions,
and data-export requests. Drop in <UserButton> on its own instead
if you only want the avatar menu.import { AuthLoading, SignedIn, SignedOut, SignIn, UserDashboard } from '@torii-js/torii-react';
export default function App() { return ( <main> <AuthLoading> <p>Loading…</p> </AuthLoading> <SignedOut> <SignIn /> </SignedOut> <SignedIn> <UserDashboard /> </SignedIn> </main> );}Run the dev server:
bun run devOpen http://localhost:5173; the sign-in card renders for signed-out
users. Click Sign up, create an account, verify the email link from
Mailpit / your inbox, and you’ll see the <UserDashboard> appear in its place.
Components
Full prop reference for <SignIn>, <SignUp>, <UserButton>,
<UserDashboard>, and <UserProfile>.
Browse →
Customize the theme
Pick a preset (shadcn / mui), override CSS tokens, or attach
per-element classes via appearance.elements.
Theming →
i18n & labels
Ship in en and da out of the box, or override every label.
Labels →
Hooks
useAuth(), useUser(), and useAuthFetch() for reading auth
state and calling your API.
Hooks →
First-party cookies (required)
Before production, wire up a proxy or CNAME so Safari doesn’t silently sign your users out. Set up →
Your dev origin isn’t in the application’s allowed-origins list. Open the
dashboard → Settings → Allowed origins and add the exact URL the
browser sends from (scheme + host + port, no trailing slash).
http://localhost:5173 and http://127.0.0.1:5173 are different; add
the one the browser is actually using.
<SignIn> renders but submit returns 401 UnauthorizedAlmost always one of:
pk_live_… key against a sandbox environment, or
vice-versa. Use the pk_test_… key during local development.useAuth must be used inside <ToriiProvider> thrown at runtimeA component calling useAuth, useAuthFetch, or any control component
(<SignedIn>, <SignedOut>, <Show>) is rendering outside the
provider. In Next.js this usually means you need a 'use client' wrapper
around <ToriiProvider> imported into the root layout.
If something else is going wrong, mail hello@torii.so with the error and a code snippet, and we’ll respond inside one business day.