Protected Routes
Guard routes and UI sections based on authentication state.
There are several patterns for protecting routes. Pick the one that fits your app structure.
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk/react';
function Page() {
return (
<>
<WhenAuthenticated>
<Dashboard />
</WhenAuthenticated>
<WhenUnauthenticated>
<LoginPage />
</WhenUnauthenticated>
</>
);
}Pattern 1: Component wrapping
Wrap sections of your UI with WhenAuthenticated and WhenUnauthenticated. This is the simplest approach for pages with mixed content.
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk/react';
function HomePage() {
return (
<div>
<h1>Welcome to the app</h1>
<WhenAuthenticated>
<p>
You are signed in. Go to your <a href="/dashboard">Dashboard</a>.
</p>
</WhenAuthenticated>
<WhenUnauthenticated>
<p>Sign in to access your dashboard.</p>
</WhenUnauthenticated>
</div>
);
}Handling the loading flash
WhenAuthenticated and WhenUnauthenticated render nothing while the session is resolving (unless you pass loadingComponent — see below). If you see a flash of the wrong UI, add an explicit loading check:
import {
useSaaSAuth,
WhenAuthenticated,
WhenUnauthenticated,
} from '@buildbase/sdk/react';
function HomePage() {
const { isLoading } = useSaaSAuth();
if (isLoading) return <Spinner />;
return (
<>
<WhenAuthenticated>
<Dashboard />
</WhenAuthenticated>
<WhenUnauthenticated>
<LandingPage />
</WhenUnauthenticated>
</>
);
}Pattern 2: Redirect unauthenticated users
Use useSaaSAuth() with your router to redirect users who are not signed in.
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useSaaSAuth } from '@buildbase/sdk/react';
function SettingsPage() {
const { status, isAuthenticated } = useSaaSAuth();
const router = useRouter();
useEffect(() => {
if (status !== 'loading' && !isAuthenticated) {
router.push('/login');
}
}, [status, isAuthenticated, router]);
if (!isAuthenticated) return null;
return <div>Settings content</div>;
}Pattern 3: Layout-level protection
Protect an entire section of your app by wrapping the layout instead of individual pages. Every page under this layout is automatically guarded.
import {
useSaaSAuth,
WhenAuthenticated,
WhenUnauthenticated,
} from '@buildbase/sdk/react';
function ProtectedLayout({ children }: { children: React.ReactNode }) {
const { signIn } = useSaaSAuth();
return (
<>
<WhenAuthenticated>
<nav>Dashboard Nav</nav>
<main>{children}</main>
</WhenAuthenticated>
<WhenUnauthenticated>
<div>
<p>You must sign in to continue.</p>
<button onClick={() => signIn()}>Sign In</button>
</div>
</WhenUnauthenticated>
</>
);
}Now every page under this layout (/dashboard, /dashboard/settings, /dashboard/billing) is protected without repeating auth checks.
loadingComponent and fallbackComponent
Both WhenAuthenticated and WhenUnauthenticated accept two optional props:
| Prop | Type | Default | Description |
|---|---|---|---|
loadingComponent | React.ReactNode | null | Rendered while the auth status resolves |
fallbackComponent | React.ReactNode | null | Rendered when the condition is not met |
import { WhenAuthenticated } from '@buildbase/sdk/react';
function DashboardPage() {
return (
<WhenAuthenticated
loadingComponent={<Spinner />}
fallbackComponent={<LandingPage />}
>
<Dashboard />
</WhenAuthenticated>
);
}Pattern 4: Permission-gated sections
Once a user is authenticated, you may need to restrict parts of the UI based on their permissions. Use WhenPermission to conditionally render based on roles.
import {
Permission,
WhenAuthenticated,
WhenPermission,
} from '@buildbase/sdk/react';
function Dashboard() {
return (
<WhenAuthenticated>
<h1>Dashboard</h1>
<WhenPermission permission={Permission.WORKSPACE_SETTINGS_EDIT}>
<a href="/dashboard/admin">Admin Dashboard</a>
</WhenPermission>
<WhenPermission permission={Permission.WORKSPACE_BILLING_VIEW}>
<a href="/dashboard/billing">Billing</a>
</WhenPermission>
</WhenAuthenticated>
);
}Tip
Permission checks only work inside WhenAuthenticated or after confirming
isAuthenticated is true. WhenPermission resolves against the user's role
in the current workspace — the same data usePermissions() returns.
When to use which pattern
| Pattern | Best for | Trade-off |
|---|---|---|
| Component wrapping | Pages with mixed public/private content | More markup per page |
| Redirect | Hard-gated pages where unauthenticated users should not see any content | Requires router integration |
| Layout-level | App sections where every nested route needs auth | All-or-nothing — no mixed content |
| Permission-gated | Showing/hiding features based on roles | Requires permissions to be configured in the dashboard |
Next Steps
- Sessions & Tokens — Understand session lifecycle and token management.
- Permissions Overview — Configure roles and permissions for your app.