diff --git a/main/config/navigation/quickstarts.json b/main/config/navigation/quickstarts.json
index c94c05b01a..b45a988344 100644
--- a/main/config/navigation/quickstarts.json
+++ b/main/config/navigation/quickstarts.json
@@ -18,6 +18,7 @@
"pages": [
"docs/quickstart/webapp/nextjs",
"docs/quickstart/webapp/tanstack-start",
+ "docs/quickstart/webapp/react-router",
"docs/quickstart/webapp/nuxt",
"docs/quickstart/webapp/express",
"docs/quickstart/webapp/express-beta",
diff --git a/main/docs/images/icons/dark/react-router.svg b/main/docs/images/icons/dark/react-router.svg
new file mode 100644
index 0000000000..911c8f6d8e
--- /dev/null
+++ b/main/docs/images/icons/dark/react-router.svg
@@ -0,0 +1,14 @@
+
diff --git a/main/docs/images/icons/light/react-router.svg b/main/docs/images/icons/light/react-router.svg
new file mode 100644
index 0000000000..30cee1849b
--- /dev/null
+++ b/main/docs/images/icons/light/react-router.svg
@@ -0,0 +1,14 @@
+
diff --git a/main/docs/libraries.mdx b/main/docs/libraries.mdx
index 042b41d5f0..faaf50d87a 100644
--- a/main/docs/libraries.mdx
+++ b/main/docs/libraries.mdx
@@ -26,6 +26,7 @@ Have a traditional web application that runs on a server? Auth0 maintains these
+
diff --git a/main/docs/quickstart/webapp/react-router.mdx b/main/docs/quickstart/webapp/react-router.mdx
new file mode 100644
index 0000000000..52afad9077
--- /dev/null
+++ b/main/docs/quickstart/webapp/react-router.mdx
@@ -0,0 +1,428 @@
+---
+title: Add Login to Your React Router Application
+sidebarTitle: React Router
+description: This guide demonstrates how to integrate Auth0 with a React Router application (framework mode, v7 or later) using the Auth0 React Router SDK.
+mode: wide
+validatedOn: 2026-09-17
+---
+
+import {AuthCodeBlock} from "/snippets/AuthCodeBlock.jsx";
+import {CreateInteractiveApp} from "/snippets/recipe.jsx";
+import {HowToSchema} from "/snippets/HowToSchema.jsx";
+
+
+
+
+ `@auth0/auth0-react-router` is currently in **beta** (`1.0.0-beta.2`). The API may change before the stable 1.0 release.
+
+
+
+If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
+
+**Install:**
+
+```bash
+npx skills add auth0/agent-skills --skill auth0
+```
+
+**Then ask your AI assistant:**
+
+```text
+Add Auth0 authentication to my React Router app
+```
+
+Your AI assistant will automatically create your Auth0 application, fetch credentials, install `@auth0/auth0-react-router`, configure the provider, and set up your routes. [Full agent skills documentation →](/docs/quickstart/agent-skills)
+
+
+
+ **Prerequisites:** Before you begin, ensure you have the following installed:
+
+ - **[Node.js](https://nodejs.org/en/download)** 18 or newer (20 LTS recommended)
+ - **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 9+, **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+, or **[pnpm](https://pnpm.io/installation)** 8+
+ - **[jq](https://jqlang.org/)** - Required for Auth0 CLI setup
+ - React Router framework mode, v7 or later (`react-router.config.ts` present)
+
+
+
+## Get Started
+
+This quickstart demonstrates how to add Auth0 authentication to a React Router application. You'll build a secure app with login, logout, and user profile features using the Auth0 React Router SDK. The SDK handles the OIDC flow server-side and stores the session in a JWE-encrypted cookie — tokens never reach the browser.
+
+export function generateRandomString(length) {
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ return Array.from({length}, () => chars[Math.floor(Math.random() * chars.length)]).join('');
+}
+
+export const envSnippet = `AUTH0_DOMAIN={yourDomain}
+AUTH0_CLIENT_ID={yourClientId}
+AUTH0_CLIENT_SECRET={yourClientSecret}
+AUTH0_SESSION_SECRET=${generateRandomString(32)}
+AUTH0_APP_BASE_URL=http://localhost:5173`;
+
+
+
+ Create a new React Router project for this Quickstart:
+
+ ```shellscript
+ npx create-react-router@latest my-app
+ ```
+
+ Open the project:
+
+ ```shellscript
+ cd my-app && npm install
+ ```
+
+
+ Skip this step if you are adding Auth0 to an existing React Router app.
+
+
+
+
+ ```shellscript
+ npm install @auth0/auth0-react-router
+ ```
+
+
+
+ Create an Auth0 application and set the callback and logout URLs.
+
+
+
+
+
+
+
+ Run the following command from your project's root directory to create an Auth0 app and generate a `.env` file:
+
+
+ ```shellscript Mac
+ # Install Auth0 CLI (if not already installed)
+ brew tap auth0/auth0-cli && brew install auth0
+
+ # Set up Auth0 app and generate .env file
+ auth0 qs setup --app --type regular --framework react-router --port 5173 --name "My React Router App"
+ ```
+
+ ```powershell Windows
+ # Install Auth0 CLI (if not already installed)
+ scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
+ scoop install auth0
+
+ # Set up Auth0 app and generate .env file
+ auth0 qs setup --app --type regular --framework react-router --port 5173 --name "My React Router App"
+ ```
+
+
+
+ This command will create an Auth0 Regular Web Application configured for `http://localhost:5173` and generate a `.env` file with all required credentials. Skip step 4 if you use this option.
+
+
+
+
+ 1. Go to [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > Applications**
+ 2. Click **Create Application**, enter a name, and select **Regular Web Application**
+ 3. Click **Create**
+ 4. Open the **Settings** tab (Application Settings)
+ 5. Set the following fields:
+
+ | Field | Value |
+ |-------|-------|
+ | Allowed Callback URLs | `http://localhost:5173/auth/callback` |
+ | Allowed Logout URLs | `http://localhost:5173` |
+
+ 6. Click **Save Changes**
+ 7. Copy **Domain** and **Client ID** from Application Settings — you will use them in the next step
+
+
+
+
+
+ Create a `.env` file at the root of your project:
+
+
+
+ | Variable | Where to find it |
+ |----------|-----------------|
+ | `AUTH0_DOMAIN` | Application Settings → Domain |
+ | `AUTH0_CLIENT_ID` | Application Settings → Client ID |
+ | `AUTH0_CLIENT_SECRET` | Application Settings → Client Secret |
+ | `AUTH0_SESSION_SECRET` | A random 32+ character string — auto-generated in the snippet above |
+ | `AUTH0_APP_BASE_URL` | Your app's base URL — `http://localhost:5173` for local development |
+
+
+ Never commit `.env` to version control. Add it to `.gitignore` before your first commit.
+
+
+
+
+ Create `app/auth0.server.ts`. The `.server.ts` suffix tells React Router's bundler to exclude this file from the client bundle, keeping your secrets server-only.
+
+ ```ts app/auth0.server.ts
+ import { Auth0Server, registerAuth0Instance } from '@auth0/auth0-react-router/server';
+
+ export const auth0 = new Auth0Server();
+ registerAuth0Instance(auth0);
+ ```
+
+
+
+ Create a splat route that handles all `/auth/*` paths. `handleAuth` dispatches internally to `handleLogin`, `handleCallback`, `handleLogout`, and `handleBackchannelLogout` based on the URL path and HTTP method.
+
+ ```tsx app/routes/auth.$.tsx
+ import { handleAuth } from '@auth0/auth0-react-router/server';
+ import { auth0 } from '../auth0.server';
+
+ export const loader = ({ request }: { request: Request }) =>
+ handleAuth(auth0, request);
+
+ export const action = ({ request }: { request: Request }) =>
+ handleAuth(auth0, request);
+ ```
+
+ Register the route in your route config:
+
+ ```ts app/routes.ts
+ import { type RouteConfig, route } from '@react-router/dev/routes';
+
+ export default [
+ route('auth/*', 'routes/auth.$.tsx'),
+ // ... your other routes
+ ] satisfies RouteConfig;
+ ```
+
+
+
+ Add `Auth0Provider` and `rootAuthLoader` to `app/root.tsx`. `rootAuthLoader` decrypts the session cookie and passes the auth state to the provider — no tokens are sent to the browser.
+
+ ```tsx app/root.tsx expandable
+ import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router';
+ import { Auth0Provider } from '@auth0/auth0-react-router';
+ import { rootAuthLoader } from '@auth0/auth0-react-router/server';
+ import type { Route } from './+types/root';
+
+ export const loader = ({ request }: Route.LoaderArgs) =>
+ rootAuthLoader(request);
+
+ export default function Root() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ ```
+
+
+ `Auth0Provider` reads session data from `useRouteLoaderData('root')`, so the root route must have the id `root`. With file-based routing React Router sets this from the filename automatically. With a custom route config, pass `{ id: 'root' }` to the `layout()` call.
+
+
+
+
+ Use the built-in components to show login and logout controls. `LoginButton` redirects to `/auth/login` and `LogoutButton` redirects to `/auth/logout`. Auth0 handles the OIDC flow and redirects the user back to your app after sign-in.
+
+ ```tsx app/routes/_index.tsx
+ import {
+ AuthLoading,
+ LoginButton,
+ LogoutButton,
+ SignedIn,
+ SignedOut,
+ } from '@auth0/auth0-react-router';
+
+ export default function Home() {
+ return (
+
+
Welcome
+
+
Loading…
+
+
+ Log in
+
+
+ Log out
+
+
+ );
+ }
+ ```
+
+
+
+ Use the `useUser` hook to access the authenticated user's profile in any client component. Pair it with `requireSession` in the loader to block unauthenticated requests at the server before the page renders.
+
+ ```tsx app/routes/profile.tsx
+ import { useUser } from '@auth0/auth0-react-router';
+ import { requireSession } from '@auth0/auth0-react-router/server';
+ import type { Route } from './+types/profile';
+
+ export const loader = async ({ request }: Route.LoaderArgs) => {
+ await requireSession(request);
+ return null;
+ };
+
+ export default function Profile() {
+ const user = useUser();
+
+ return (
+
+
Profile
+ {user && (
+
+
+
{user.name}
+
{user.email}
+
+ )}
+
+ );
+ }
+ ```
+
+
+
+ ```shellscript
+ npm run dev
+ ```
+
+ Open `http://localhost:5173` in your browser and click **Log in**. You will be redirected to the Auth0 Universal Login page. After signing in you will be redirected back to your app.
+
+
+
+
+ Your app now has working login and logout. The session is stored in a JWE-encrypted cookie — access tokens stay on the server and are never sent to the browser.
+
+
+## Troubleshooting
+
+
+
+
+
+**Cause:** `AUTH0_SESSION_SECRET` changed after a session cookie was issued, or the value is fewer than 32 characters.
+
+**Fix:** Clear your browser cookies for `localhost`, confirm `AUTH0_SESSION_SECRET` is at least 32 characters, and restart the dev server. To generate a new secret: `openssl rand -hex 32`.
+
+
+
+
+
+**Cause:** The redirect URL Auth0 receives does not match any value in Allowed Callback URLs.
+
+**Fix:** In [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > Applications** → select your app → **Application Settings**, confirm **Allowed Callback URLs** is set to `http://localhost:5173/auth/callback`. Remove any trailing slashes or extra whitespace, then click **Save Changes**.
+
+
+
+
+
+**Cause:** The `auth.$.tsx` splat route is missing or not registered in `routes.ts`.
+
+**Fix:** Confirm `app/routes/auth.$.tsx` exists and that `app/routes.ts` includes `route('auth/*', 'routes/auth.$.tsx')`. Restart the dev server after editing `routes.ts`.
+
+
+
+
+
+**Cause:** `rootAuthLoader` is not exported from `app/root.tsx`, or the root route does not have the id `root`.
+
+**Fix:** Confirm `app/root.tsx` exports `export const loader = ({ request }) => rootAuthLoader(request)`. With a custom route config, register the root layout as `layout('root.tsx', { id: 'root' }, [...routes])`.
+
+
+
+
+
+**Cause:** `defineRouteAuth` and `auth0Middleware` require React Router 7.9.0 or later, which introduced the middleware API.
+
+**Fix:** Upgrade `react-router` to `>=7.9.0`, or protect routes individually using `requireSession` / `requireUser` in each loader instead.
+
+
+
+
+
+## Advanced Usage
+
+
+
+
+
+Add `AUTH0_AUDIENCE` to `.env` with your API's identifier (from [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > APIs** → **API Settings → Identifier**). Then use `getAccessToken` in a loader — the token never reaches the browser:
+
+```ts app/routes/data.tsx
+import { getAccessToken } from '@auth0/auth0-react-router/server';
+import { TokenError } from '@auth0/auth0-react-router/errors';
+
+export const loader = async ({ request }) => {
+ let token: string;
+ try {
+ token = await getAccessToken(request);
+ } catch (err) {
+ if (err instanceof TokenError) {
+ return new Response(null, { status: 302, headers: { Location: '/auth/login' } });
+ }
+ throw err;
+ }
+ const data = await fetch('https://api.example.com/items', {
+ headers: { Authorization: `Bearer ${token}` },
+ }).then(r => r.json());
+ return { data };
+};
+```
+
+
+
+
+
+Use `defineRouteAuth` middleware (React Router ≥ 7.9.0) to enforce roles at the route level. Roles are read from the `https://auth0.com/claims/roles` claim by default:
+
+```ts app/routes/admin.tsx
+import { defineRouteHandle } from '@auth0/auth0-react-router';
+import { defineRouteAuth, auth0UserContext } from '@auth0/auth0-react-router/server';
+
+export const handle = defineRouteHandle({ role: 'admin' });
+
+export const middleware = defineRouteAuth({ role: 'admin' }).middleware;
+
+export const loader = ({ context }) => {
+ const user = context.get(auth0UserContext);
+ return { user };
+};
+```
+
+Requests without the required role receive a `403`.
+
+
+
+
+
+The SDK can run in a purely client-side mode backed by `@auth0/auth0-spa-js`. Add `VITE_AUTH0_DOMAIN` and `VITE_AUTH0_CLIENT_ID` to your `.env` — `Auth0Provider` detects these automatically and switches to the PKCE flow. No other code changes are required.
+
+```shellscript
+# .env additions for SPA mode
+VITE_AUTH0_DOMAIN={yourDomain}
+VITE_AUTH0_CLIENT_ID={yourClientId}
+```
+
+
+Do not set both `AUTH0_*` and `VITE_AUTH0_*` variables at the same time. Hybrid mode is not supported — when both are present, SPA logout will not clear the server-side session cookie.
+
+
+
+
+
diff --git a/main/docs/quickstarts.mdx b/main/docs/quickstarts.mdx
index 7b1ec2482a..752427a8bc 100644
--- a/main/docs/quickstarts.mdx
+++ b/main/docs/quickstarts.mdx
@@ -178,6 +178,17 @@ Traditional web app that runs on the server
}}
/>
+
+