Skip to main content
Version: 2.x (Latest)

Integration Guide

This guide goes beyond the components and hooks reference and shows how to wire @authorizerdev/authorizer-react into a real application: protecting routes, calling your backend with the access token, rendering UI by role, and integrating with Next.js.

All patterns build on the AuthorizerProvider + useAuthorizer() pair — set up the provider once near the root, then read user, token, and loading anywhere below it.

Provider setup​

Wrap your app in AuthorizerProvider and import the stylesheet once:

import { AuthorizerProvider } from '@authorizerdev/authorizer-react';
import '@authorizerdev/authorizer-react/styles.css';

export default function Root({ children }) {
return (
<AuthorizerProvider
config={{
authorizerURL: 'https://your-instance.authorizer.dev',
redirectURL: window.location.origin,
clientID: 'YOUR_CLIENT_ID',
}}
onStateChangeCallback={async ({ user, token }) => {
// Fires on every auth-state change — good place to sync
// analytics, external stores, etc.
console.log('auth state changed', { user, token });
}}
>
{children}
</AuthorizerProvider>
);
}

The provider fetches the server's feature flags from /meta and automatically refreshes the access token before it expires, so useAuthorizer() always reflects the live session.

Protecting routes​

Read token and loading from the hook and branch on them. While the provider is restoring the session, loading is true — render a spinner, not your login screen, to avoid a flash.

import { Routes, Route } from 'react-router-dom';
import { useAuthorizer, Authorizer } from '@authorizerdev/authorizer-react';
import Dashboard from './Dashboard';

function App() {
const { token, loading } = useAuthorizer();

if (loading) return <h1>Loading…</h1>;

if (!token) {
return <Authorizer onLogin={(data) => console.log('logged in', data)} />;
}

return (
<Routes>
<Route path="/" element={<Dashboard />} />
</Routes>
);
}

For a reusable guard component:

function RequireAuth({ children }) {
const { token, loading } = useAuthorizer();
if (loading) return <h1>Loading…</h1>;
if (!token) return <Authorizer />;
return children;
}

// <RequireAuth><Dashboard /></RequireAuth>

Calling your backend with the token​

The token object exposes access_token (and id_token, refresh_token). Attach it as a bearer credential on your API calls:

import { useAuthorizer } from '@authorizerdev/authorizer-react';

function useApi() {
const { token } = useAuthorizer();

return async function api(path, options = {}) {
const res = await fetch(`https://api.example.com${path}`, {
...options,
headers: {
...options.headers,
'Content-Type': 'application/json',
Authorization: token ? `Bearer ${token.access_token}` : '',
},
});
if (!res.ok) throw new Error(`API ${res.status}`);
return res.json();
};
}

Your backend validates that token with Authorizer's validate_jwt_token (or the JWKS at /.well-known/jwks.json).

Permission-aware UI with FGA​

If you use fine-grained authorization, ask the server what the user can do via the REST or GraphQL check_permissions endpoint, using the same bearer token, and render accordingly:

const api = useApi();

const { results } = await api('/v1/check_permissions', {
method: 'POST',
body: JSON.stringify({
checks: [{ relation: 'can_edit', object: 'document:1' }],
}),
});

const canEdit = results[0]?.allowed;
// {canEdit && <EditButton />}

Rendering UI by role​

user.roles holds the roles assigned at signup/login. Gate UI on it:

import { useAuthorizer } from '@authorizerdev/authorizer-react';

function AdminPanel() {
const { user } = useAuthorizer();
const isAdmin = user?.roles?.includes('admin');

if (!isAdmin) return null;
return <div>{/* admin-only UI */}</div>;
}

You can also restrict which roles a login grants by passing roles to the auth components, e.g. <Authorizer roles={['user']} />.

Logout​

useAuthorizer() returns a logout function that clears the session both server-side and in context:

function LogoutButton() {
const { logout } = useAuthorizer();
return <button onClick={logout}>Log out</button>;
}

Multi-factor authentication and passkeys​

Authorizer (and the individual AuthorizerSignup / AuthorizerBasicAuthLogin / AuthorizerPasskeyLogin components) already handle MFA end-to-end during login and signup: when the backend offers or requires a second factor, they automatically render the setup, verification, or locked-account screens for you — no extra wiring needed.

To let a signed-in user manage their own second factors from a "Security settings" page, use AuthorizerMFASetup and AuthorizerPasskeyRegister directly:

import {
useAuthorizer,
AuthorizerMFASetup,
AuthorizerPasskeyRegister,
} from '@authorizerdev/authorizer-react';

function SecuritySettings() {
const { config } = useAuthorizer();

return (
<>
<h2>Two-factor authentication</h2>
<AuthorizerMFASetup
availableMfaMethods={{
totp: config.is_totp_mfa_enabled,
passkey: config.is_webauthn_enabled,
emailOtp: config.is_email_otp_mfa_enabled,
smsOtp: config.is_sms_otp_mfa_enabled,
}}
/>

<h2>Passkeys</h2>
<AuthorizerPasskeyRegister showCredentials />
</>
);
}

AuthorizerPasskeyLogin and passkey verification only render for browsers that support WebAuthn — there is no backend flag to gate them on, so gate any custom UI you build around them on isWebauthnSupported() from @authorizerdev/authorizer-js the same way.

Next.js integration​

authorizer-react is a client-side library — render the provider in a client component and keep it out of server components.

App Router​

Create a client-side providers wrapper:

// app/providers.tsx
'use client';

import { AuthorizerProvider } from '@authorizerdev/authorizer-react';
import '@authorizerdev/authorizer-react/styles.css';

export function Providers({ children }: { children: React.ReactNode }) {
return (
<AuthorizerProvider
config={{
authorizerURL: process.env.NEXT_PUBLIC_AUTHORIZER_URL!,
redirectURL: typeof window !== 'undefined' ? window.location.origin : '',
clientID: process.env.NEXT_PUBLIC_AUTHORIZER_CLIENT_ID!,
}}
>
{children}
</AuthorizerProvider>
);
}

Use it in the root layout:

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}

Then mark any component that calls useAuthorizer() or renders an Authorizer component with 'use client'.

Pages Router​

Wrap your app in pages/_app.tsx:

import type { AppProps } from 'next/app';
import { AuthorizerProvider } from '@authorizerdev/authorizer-react';
import '@authorizerdev/authorizer-react/styles.css';

export default function MyApp({ Component, pageProps }: AppProps) {
return (
<AuthorizerProvider
config={{
authorizerURL: process.env.NEXT_PUBLIC_AUTHORIZER_URL!,
redirectURL: typeof window !== 'undefined' ? window.location.origin : '',
clientID: process.env.NEXT_PUBLIC_AUTHORIZER_CLIENT_ID!,
}}
>
<Component {...pageProps} />
</AuthorizerProvider>
);
}

For SSR data fetching that needs the user, read the session cookie on the server and validate it with validate_session rather than relying on the client-side context.

Reset-password page​

Social and email flows redirect back to your redirectURL. For password resets, render AuthorizerResetPassword on the route you configured (e.g. /reset-password) — it reads the token and redirect_uri from the URL automatically:

import { AuthorizerResetPassword } from '@authorizerdev/authorizer-react';

export default function ResetPasswordPage() {
return <AuthorizerResetPassword onReset={() => (window.location.href = '/')} />;
}

See also​

  • Components — every prop of every Authorizer component.
  • Hooks — the full useAuthorizer() return shape.
  • authorizer-js — the underlying JS SDK (authorizerRef) for advanced calls.