+ );
+}
+```
+
+## Protected Routes
+
+React Router 7 supports route-level authentication using loaders. Here's how to create protected routes that require user authentication:
+
+### Creating a Protected Route
+
+Create a protected route loader that checks authentication and redirects unauthenticated users:
+
+```tsx app/routes/protected._index.tsx
+import { data, redirect, Outlet } from "react-router";
+import type { LoaderFunctionArgs, MetaFunction } from "react-router";
+import { getUser } from "./auth.$";
+
+export const meta: MetaFunction = () => {
+ return [{ title: "Protected Page - Civic Auth Demo" }];
+};
+
+export const loader = async ({ request }: LoaderFunctionArgs) => {
+ const user = await getUser(request);
+
+ if (!user) {
+ // Redirect to home page if user is not authenticated
+ return redirect("/");
+ }
+
+ return data({ user });
+};
+
+export default function ProtectedPage() {
+ return (
+
+
+
+ );
+}
+```
+
+### Protected Route Layout
+
+Create the protected route content that displays to authenticated users:
+
+```tsx app/routes/protected.tsx
+import { Link } from "react-router";
+import type { MetaFunction } from "react-router";
+import { useUser } from "@civic/auth/react-router-7/useUser";
+
+export const meta: MetaFunction = () => {
+ return [{ title: "Protected Page - Civic Auth Demo" }];
+};
+
+export default function ProtectedLayout() {
+ const { user } = useUser();
+
+ return (
+
+
+
Protected Page
+
+
+
Welcome to this protected page, {user?.name || "User"}!
+
This content is only visible to authenticated users.
+
+
+
+
+ Back to Home
+
+
+ Logout
+
+
+
+
+ );
+}
+```
+
+### How It Works
+
+1. **Route Protection**: The `protected._index.tsx` loader runs on the server before rendering the page
+2. **Authentication Check**: It uses `getUser(request)` to check if the user is authenticated
+3. **Redirect Logic**: If no user is found, it redirects to the home page using `redirect("/")`
+4. **User Data**: If authenticated, it passes the user data to the route
+5. **Protected Content**: The `protected.tsx` layout displays content only to authenticated users
+
+### Alternative Protection Patterns
+
+You can also create a reusable protection utility:
+
+```tsx app/utils/requireAuth.ts
+import { redirect } from "react-router";
+import { getUser } from "~/routes/auth.$";
+
+export async function requireAuth(request: Request) {
+ const user = await getUser(request);
+
+ if (!user) {
+ throw redirect("/auth/login");
+ }
+
+ // Additional admin-specific checks can go here
+ // Example: Check if user has admin privileges (implement according to your needs)
+ if (!isUserAdmin(user.email)) {
+ throw redirect("/");
+ }
+
+ return user;
+}
+```
+
+Then use it in any protected route:
+
+```tsx app/routes/admin.tsx
+import type { LoaderFunctionArgs } from "react-router";
+import { requireAuth } from "~/utils/requireAuth";
+
+export const loader = async ({ request }: LoaderFunctionArgs) => {
+ const user = await requireAuth(request);
+
+ return { user };
+};
+```
+
+## Advanced Configuration
+
+Civic Auth is a "low-code" solution, so most configuration takes place via the [dashboard](https://auth.civic.com). Changes you make there will be updated automatically in your integration without any code changes.
+
+You can customize the library according to your React Router 7 app's needs. Configure options when calling `createRouteHandlers`:
+
+```ts app/routes/auth.$.tsx
+import { createRouteHandlers } from "@civic/auth/react-router-7";
+
+const { createAuthLoader, getUser } = createRouteHandlers({
+ clientId: "YOUR_CLIENT_ID",
+ loginSuccessUrl: "/myCustomSuccessEndpoint",
+ callbackUrl: "/api/myroute/callback",
+ logoutUrl: "/goodbye",
+ baseUrl: "https://myapp.com",
+});
+```
+
+### Configuration Options
+
+| Field | Required | Default | Example | Description |
+| ----------------- | -------- | ---------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `clientId` | Yes | - | `2cc5633d-2c92-48da-86aa-449634f274b9` | The key obtained on signup to [auth.civic.com](https://auth.civic.com/) |
+| `loginSuccessUrl` | No | - | `/myCustomSuccessEndpoint` | In a NextJS app, we will redirect your user to this page once the login is finished. If not set, users will be sent back to the root of your app. |
+| `callbackUrl` | No | `/auth/callback` | `/api/myroute/callback` | If you cannot host Civic’s SDK handlers in the default location, you can specify a custom callback route here. This is where you must attach Civic’s GET handler as described [here](/integration/nextjs#2-create-the-civic-auth-api-route), so Civic can complete the OAuth token exchange. Use `loginSuccessUrl` to redirect after login. |
+| `logoutUrl` | No | `/` | `/goodbye` | The path your user will be sent to after a successful log-out. |
+| `baseUrl` | No | - | `https://myapp.com` | The public-facing base URL for your application. Required when deploying behind reverse proxies (Cloudfront + Vercel, AWS ALB, nginx, etc.) to ensure authentication redirects use the correct public domain instead of internal origins. |