--- name: workos-authkit-nextjs description: Integrate WorkOS AuthKit with Next.js App Router (13+). Server-side rendering required. --- # WorkOS AuthKit for Next.js ## Step 1: Fetch SDK Documentation (BLOCKING) **STOP. Do not proceed until complete.** WebFetch: `https://github.com/workos/authkit-nextjs/blob/main/README.md` The README is the source of truth. If this skill conflicts with README, follow README. ## Step 2: Pre-Flight Validation ### Project Structure - Confirm `next.config.js` or `next.config.mjs` exists - Confirm `package.json` contains `"next"` dependency ### Environment Variables Check `.env.local` for: - `WORKOS_API_KEY` - starts with `sk_` - `WORKOS_CLIENT_ID` - starts with `client_` - `NEXT_PUBLIC_WORKOS_REDIRECT_URI` - valid callback URL - `WORKOS_COOKIE_PASSWORD` - 32+ characters ## Step 3: Install SDK Detect package manager, install SDK package from README. **Verify:** SDK package exists in node_modules before continuing. ## Step 4: Version Detection (Decision Tree) Read Next.js version from `package.json`: ``` Next.js version? | +-- 16+ --> Create proxy.ts at project root | +-- 15 --> Create middleware.ts (cookies() is async - handlers must await) | +-- 13-14 --> Create middleware.ts (cookies() is sync) ``` **Critical:** File MUST be at project root (or `src/` if using src directory). Never in `app/`. **Next.js 15+ async note:** All route handlers and middleware accessing cookies must be async and properly await cookie operations. This is a breaking change from Next.js 14. Middleware/proxy code: See README for `authkitMiddleware()` export pattern. ### Existing Middleware (IMPORTANT) If `middleware.ts` already exists with custom logic (rate limiting, logging, headers, etc.), use the **`authkit()` composable function** instead of `authkitMiddleware`. **Pattern for composing with existing middleware:** ```typescript import { NextRequest, NextResponse } from 'next/server'; import { authkit, handleAuthkitHeaders } from '@workos-inc/authkit-nextjs'; export default async function middleware(request: NextRequest) { // 1. Get auth session and headers from AuthKit const { session, headers, authorizationUrl } = await authkit(request); const { pathname } = request.nextUrl; // 2. === YOUR EXISTING MIDDLEWARE LOGIC === // Rate limiting, logging, custom headers, etc. const rateLimitResult = checkRateLimit(request); if (!rateLimitResult.allowed) { return new NextResponse('Too Many Requests', { status: 429 }); } // 3. Protect routes - redirect to auth if needed if (pathname.startsWith('/dashboard') && !session.user && authorizationUrl) { return handleAuthkitHeaders(request, headers, { redirect: authorizationUrl }); } // 4. Continue with AuthKit headers properly handled return handleAuthkitHeaders(request, headers); } ``` **Key functions:** - `authkit(request)` - Returns `{ session, headers, authorizationUrl }` for composition - `handleAuthkitHeaders(request, headers, options?)` - Ensures AuthKit headers pass through correctly - For rewrites, use `partitionAuthkitHeaders()` and `applyResponseHeaders()` (see README) **Critical:** Always return via `handleAuthkitHeaders()` to ensure `withAuth()` works in pages. ## Step 5: Create Callback Route Parse `NEXT_PUBLIC_WORKOS_REDIRECT_URI` to determine route path: ``` URI path --> Route location /auth/callback --> app/auth/callback/route.ts /callback --> app/callback/route.ts ``` Use `handleAuth()` from SDK. Do not write custom OAuth logic. **CRITICAL for Next.js 15+:** The route handler MUST be async and properly await handleAuth(): ```typescript // CORRECT - Next.js 15+ requires async route handlers export const GET = handleAuth(); // If handleAuth returns a function, ensure it's awaited in request context ``` Check README for exact usage. If build fails with "cookies outside request scope", the handler is likely missing async/await. ## Step 6: Provider Setup (REQUIRED) **CRITICAL:** You MUST wrap the app in `AuthKitProvider` in `app/layout.tsx`. This is required for: - Client-side auth state via `useAuth()` hook - Consistent auth UX across client/server boundaries - Proper migration from Auth0 (which uses client-side auth) ```tsx // app/layout.tsx import { AuthKitProvider } from '@workos-inc/authkit-nextjs'; export default function RootLayout({ children }: { children: React.ReactNode }) { return (