Documentation

Protect a route with React & Next.js

AdminUpdated Sep 11, 2026

Protect a route with React & Next.js

This quickstart adds Atlas to a React or Next.js app: a provider, a sign-in UI, and a protected route. It takes a few minutes and uses your publishable key.

React

1. Install

npm install @atlas/react

2. Wrap your app in the provider

<AtlasProvider> boots the session, completes any OAuth/hosted-page redirect, and schedules token refresh. Give it your publishable key and your instance's Frontend API origin:

import { AtlasProvider } from '@atlas/react';

export function Root() {
  return (
    <AtlasProvider
      publishableKey="pk_live_your_key"
      frontendApi="https://accounts.yourapp.com"
    >
      <App />
    </AtlasProvider>
  );
}

3. Render sign-in and user state

<SignedIn> / <SignedOut> render by auth state; <SignIn> is the prebuilt flow; <UserButton> is the account menu:

import { SignedIn, SignedOut, SignIn, UserButton } from '@atlas/react';

function Header() {
  return (
    <>
      <SignedOut>
        <SignIn />
      </SignedOut>
      <SignedIn>
        <UserButton />
      </SignedIn>
    </>
  );
}

4. Read the user from hooks

import { useUser, useAuth } from '@atlas/react';

function Profile() {
  const { isLoaded, isSignedIn, user } = useUser();
  const { getToken, signOut } = useAuth();

  if (!isLoaded) return null;          // still booting
  if (!isSignedIn) return <p>Please sign in.</p>;
  return <p>Hello, {user.firstName}</p>;
}

Next.js (App Router)

1. Install

npm install @atlas/nextjs

2. Protect routes with middleware

atlasMiddleware verifies the session and redirects signed-out users away from anything not listed as public. Unlisted routes are protected by default, so a new page is safe from the moment you add it:

// middleware.ts
import { atlasMiddleware } from '@atlas/nextjs';

export default atlasMiddleware({
  jwksUrl: 'https://accounts.yourapp.com/.well-known/jwks.json',
  issuer: 'https://accounts.yourapp.com',
  publicRoutes: ['/', '/sign-in(.*)', '/sign-up(.*)'],
  signInUrl: '/sign-in',
});

export const config = { matcher: ['/((?!_next|.*\\..*).*)'] };

3. Read auth in a server component or route handler

Create an auth() helper once, then call it wherever you need the session. It exposes has() and protect() for authorization — the same condition set as React's <Protect>:

// atlas.ts
import { createAuthHelper } from '@atlas/nextjs';

export const auth = createAuthHelper({
  jwksUrl: 'https://accounts.yourapp.com/.well-known/jwks.json',
  issuer: 'https://accounts.yourapp.com',
});
// app/api/billing/route.ts
import { auth } from '@/atlas';

export async function POST(request: Request) {
  const a = await auth(request);
  a.protect({ permission: 'org:billing:manage' }); // throws → 403 if not held
  // …do the privileged work
}

Next

Was this page helpful?