Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Advanced Clerk auth patterns for Next.js: Server Actions, middleware, caching, and App Router integration.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/middleware-strategies.md
1# Middleware Strategies23> **Filename:** `proxy.ts` (Next.js <=15: `middleware.ts`). The code is identical; only the filename changes.45## Public-First (marketing sites, blogs)67Protect specific routes, allow everything else:89```typescript10import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';1112const isProtectedRoute = createRouteMatcher([13'/dashboard(.*)',14'/settings(.*)',15'/api/private(.*)',16]);1718export default clerkMiddleware(async (auth, req) => {19if (isProtectedRoute(req)) await auth.protect();20});2122export const config = {23matcher: [24'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',25'/(api|trpc)(.*)',26],27};28```2930## Protected-First (internal tools, dashboards)3132Block everything, allow specific public routes:3334```typescript35import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';3637const isPublicRoute = createRouteMatcher([38'/',39'/sign-in(.*)',40'/sign-up(.*)',41'/api/public(.*)',42]);4344export default clerkMiddleware(async (auth, req) => {45if (!isPublicRoute(req)) await auth.protect();46});47```4849## Permission-Gated Routes5051For B2B apps where some routes require a specific permission or role, pass a callback to `auth.protect()`. Clerk returns a 404 if the check fails:5253```typescript54import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';5556const isInvoiceRoute = createRouteMatcher(['/invoices(.*)']);57const isAdminRoute = createRouteMatcher(['/admin(.*)']);5859export default clerkMiddleware(async (auth, req) => {60if (isInvoiceRoute(req)) {61await auth.protect((has) => has({ permission: 'org:invoices:create' }));62}63if (isAdminRoute(req)) {64await auth.protect((has) =>65has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })66);67}68});69```7071Prefer permissions over roles — permissions are more granular and easier to reassign across roles in the Dashboard.7273> **Core 2 ONLY (skip if current SDK):** Middleware uses synchronous `clerkMiddleware((auth, req) => { auth().protect((has) => ...) })`. Note `auth()` is called as a function (not `auth.protect`) and the callback signature is the same.7475## Token-Based Protection (Machine APIs)7677For routes that accept different token types (OAuth tokens, machine-to-machine tokens, API keys), pass a `token` option to `auth.protect()`:7879```typescript80const isMachineApi = createRouteMatcher(['/api/machine(.*)']);81const isPublicApi = createRouteMatcher(['/api/public(.*)']);8283export default clerkMiddleware(async (auth, req) => {84if (isMachineApi(req)) await auth.protect({ token: 'm2m_token' });85if (isPublicApi(req)) await auth.protect({ token: 'any' });86});87```8889Token types: `'session_token'` (default, browser sessions), `'oauth_token'`, `'api_key'`, `'m2m_token'`, `'any'` (accept any valid token).9091> **Core 2 ONLY (skip if current SDK):** Token-type protection requires Core 3. In Core 2, `auth().protect()` only accepts a callback (no `token` option) and only validates session tokens.9293## Session Tasks9495When session tasks are enabled (e.g., forced password reset, MFA setup), users may have a `pending` session status. You can handle this in middleware:9697```typescript98export default clerkMiddleware(async (auth, req) => {99const { sessionStatus } = await auth();100101// Redirect pending sessions to task completion page102if (sessionStatus === 'pending') {103return NextResponse.redirect(new URL('/sign-in/tasks', req.url));104}105106if (isProtectedRoute(req)) await auth.protect();107});108```109110> **Core 2 ONLY (skip if current SDK):** `sessionStatus` is not available. Session tasks do not exist in Core 2.111112[Docs](https://clerk.com/docs/reference/nextjs/clerk-middleware)113