workos-authkit-nextjs
Original:🇺🇸 English
Not Translated
Integrate WorkOS AuthKit with Next.js App Router (13+). Server-side rendering required.
2installs
Sourceworkos/skills
Added on
NPX Install
npx skill4agent add workos/skills workos-authkit-nextjsSKILL.md Content
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.mdThe README is the source of truth. If this skill conflicts with README, follow README.
Step 2: Pre-Flight Validation
Project Structure
- Confirm or
next.config.jsexistsnext.config.mjs - Confirm contains
package.jsondependency"next"
Environment Variables
Check for:
.env.local- - starts with
WORKOS_API_KEYsk_ - - starts with
WORKOS_CLIENT_IDclient_ - - valid callback URL
NEXT_PUBLIC_WORKOS_REDIRECT_URI - - 32+ characters
WORKOS_COOKIE_PASSWORD
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.jsonNext.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 if using src directory). Never in .
src/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 export pattern.
authkitMiddleware()Existing Middleware (IMPORTANT)
If already exists with custom logic (rate limiting, logging, headers, etc.), use the composable function instead of .
middleware.tsauthkit()authkitMiddlewarePattern 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:
- - Returns
authkit(request)for composition{ session, headers, authorizationUrl } - - Ensures AuthKit headers pass through correctly
handleAuthkitHeaders(request, headers, options?) - For rewrites, use and
partitionAuthkitHeaders()(see README)applyResponseHeaders()
Critical: Always return via to ensure works in pages.
handleAuthkitHeaders()withAuth()Step 5: Create Callback Route
Parse to determine route path:
NEXT_PUBLIC_WORKOS_REDIRECT_URIURI path --> Route location
/auth/callback --> app/auth/callback/route.ts
/callback --> app/callback/route.tsUse from SDK. Do not write custom OAuth logic.
handleAuth()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 contextCheck 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 in .
AuthKitProviderapp/layout.tsxThis is required for:
- Client-side auth state via hook
useAuth() - 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 (
<html lang="en">
<body>
<AuthKitProvider>{children}</AuthKitProvider>
</body>
</html>
);
}Check README for exact import path - it may be a subpath export like .
@workos-inc/authkit-nextjs/componentsDo NOT skip this step even if using server-side auth patterns elsewhere.
Step 7: UI Integration
Add auth UI to using SDK functions. See README for , , usage.
app/page.tsxgetUsergetSignInUrlsignOutVerification Checklist (ALL MUST PASS)
Run these commands to confirm integration. Do not mark complete until all pass:
bash
# 1. Check middleware/proxy exists (one should match)
ls proxy.ts middleware.ts src/proxy.ts src/middleware.ts 2>/dev/null
# 2. CRITICAL: Check AuthKitProvider is in layout (REQUIRED)
grep "AuthKitProvider" app/layout.tsx || echo "FAIL: AuthKitProvider missing from layout"
# 3. Check callback route exists
find app -name "route.ts" -path "*/callback/*"
# 4. Build succeeds
npm run buildIf check #2 fails: Go back to Step 6 and add AuthKitProvider. This is not optional.
Error Recovery
"cookies was called outside a request scope" (Next.js 15+)
Most common cause: Route handler not properly async or missing await.
Fix for callback route:
- Check that is exported directly:
handleAuth()export const GET = handleAuth(); - If using custom wrapper, ensure it's and awaits any cookie operations
async - Verify authkit-nextjs SDK version supports Next.js 15+ (check README for compatibility)
- Never call at module level - only inside request handlers
cookies()
This error causes OAuth codes to expire ("invalid_grant"), so fix the handler first.
"middleware.ts not found"
- Check: File at project root or , not inside
src/app/ - Check: Filename matches Next.js version (proxy.ts for 16+, middleware.ts for 13-15)
"Cannot use getUser in client component"
- Check: Component has no directive, or
'use client' - Check: Move auth logic to server component/API route
"Module not found" for SDK import
- Check: SDK installed before writing imports
- Check: SDK package directory exists in node_modules
"withAuth route not covered by middleware"
- Check: Middleware/proxy file exists at correct location
- Check: Matcher config includes the route path
Build fails after AuthKitProvider
- Check: README for correct import path (may be subpath export)
- Check: No client/server boundary violations
NEXTPUBLIC prefix issues
- Client components need prefix
NEXT_PUBLIC_* - Server components use plain env var names