Sign In & Sign Out
Handle sign-in, sign-out, and user state in your React app.
useSaaSAuth() is the primary hook for authentication. Call signIn() to redirect to the BuildBase auth portal, signOut() to end the session.
Step by step, with screenshots: Set up email and password and Set up magic links and email codes.
signOut() revokes the session on the server and then clears local state, so the session id cannot be reused afterwards. It returns a promise, and local state is cleared even if the revoke fails - a user who pressed sign out is signed out in the browser either way.
Note
Server-side revocation landed in SDK 0.0.70. On 0.0.68 and earlier
signOut() only cleared local state, and the session stayed valid until it
expired. Upgrade if you rely on signing out to end a session.
import { useSaaSAuth } from '@buildbase/sdk/react';
function App() {
const { user, isAuthenticated, signIn, signOut } = useSaaSAuth();
if (!isAuthenticated) {
return <button onClick={() => signIn()}>Sign In</button>;
}
return (
<div>
<p>Welcome, {user?.name}</p>
<button onClick={() => signOut()}>Sign Out</button>
</div>
);
}useSaaSAuth() returns
| Property | Type | Description |
|---|---|---|
user | AuthUser or undefined | The authenticated user: id, name, email, emailVerified, role, org, clientId, image? |
session | AuthSession or null | The current session: user, sessionId, expires |
status | 'loading' | 'redirecting' | 'authenticated' | 'unauthenticated' | 'authenticating' | Session resolution state |
isLoading | boolean | True while session is resolving |
isRedirecting | boolean | True while redirecting to the auth portal |
isAuthenticated | boolean | True when signed in |
signIn(returnUrl?) | function | Redirect to sign-in portal |
signOut(options?) | function | Revoke the session server-side, then clear local state. { everywhere: true } ends every session |
requireReverification(options?) | function | Re-confirm before a sensitive change. See Confirm it's you |
openWorkspaceSettings(section?) | function | Open workspace settings panel |
openCreditStore() | function | Open the credit store |
openPlanPicker() | function | Open the plan picker |
user also carries mfaEnabled while the person has a second step on, phone and phoneVerified when they have a phone number, username, externalId for someone imported from another system, the owner's custom claims as claims, canChangeEmail, isAnonymous for a guest and deleteAfter while a deletion is scheduled. session carries authTime and amr, how recently and how the person signed in, and impersonation while an app owner is signed in as them.
Signing out everywhere
signOut() ends the session it was called from. Pass { everywhere: true } to
end every session that user has, on every device - the usual response to a lost
laptop or a password someone else may have seen. It also ends the access of
every agent the person connected, and each asks for their consent again.
function SignOutButtons() {
const { signOut } = useSaaSAuth();
return (
<>
<button onClick={() => signOut()}>Sign out</button>
<button onClick={() => signOut({ everywhere: true })}>
Sign out everywhere
</button>
</>
);
}Three different jobs, so three different calls:
| To end | Call | Where |
|---|---|---|
| This session | signOut() | useSaaSAuth() |
| Every session for this user | signOut({ everywhere: true }) | useSaaSAuth() |
| One other session | revoke(id) | useSessions(), see sessions and tokens |
| Every session on a device | signOut(deviceId) | useDevices(), same page |
Outside React, AuthApi.logout(sessionId?, { all? }) does the same thing.
Conditional rendering
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk/react';
function Page() {
return (
<>
<WhenAuthenticated>
<Dashboard />
</WhenAuthenticated>
<WhenUnauthenticated>
<LoginPage />
</WhenUnauthenticated>
</>
);
}Handle loading state
The SDK checks the session on first render. Always handle loading:
const { isLoading, isAuthenticated } = useSaaSAuth();
if (isLoading) return <Spinner />;
if (!isAuthenticated) return <SignInPage />;
return <Dashboard />;Error handling
Auth errors surface through the handleAuthentication callback in your provider config. If the callback throws or the auth code exchange fails, the SDK does not update the session - the user stays unauthenticated.
// In your SaaSOSProvider auth config
auth={{
clientId: 'your-client-id',
redirectUrl: '/callback',
callbacks: {
getSession: async () => localStorage.getItem('sessionId'),
onSignOut: async () => localStorage.removeItem('sessionId'),
handleAuthentication: async (code) => {
try {
const res = await fetch('/api/auth/verify', {
method: 'POST',
body: JSON.stringify({ code }),
});
if (!res.ok) throw new Error('Auth failed');
const data = await res.json();
return { sessionId: data.sessionId };
} catch (error) {
// Show a toast, redirect to an error page, or log
console.error('Authentication failed:', error);
throw error; // Re-throw so the SDK knows auth failed
}
},
},
}}Common failure scenarios:
- Network error - the callback fetch fails. Show a retry prompt.
- Invalid code - the auth code expired or was already used. The user needs to sign in again.
- Server error - your backend returned a non-200 response. Check server logs.
Preserve return URL
Pass a URL to signIn() to redirect the user back after authentication:
<button onClick={() => signIn('/settings')}>Sign in to view settings</button>Next Steps
- Protected Routes - Guard routes and sections of your app.