### Step 1: Set up Clerk Middleware (recommended current pattern)
−- Clerk's middleware integrates with Next.js via a proxy file. For Next.js ≤15 name it `middleware.ts`; otherwise `proxy.ts` (Clerk docs).
+- Clerk's middleware integrates with Next.js via a proxy file. Name the file proxy.ts at the project root (or src/) as shown in Clerk docs. Note: when using older Next.js releases (<=15), Next.js expects the filename middleware.ts — the code is identical; only the filename differs (Clerk docs).
−- The minimal recommended middleware attaches Clerk token parsing to requests but does not implicitly protect all routes; protection is opt-in (clerkMiddleware default behavior).
Example (proxy.ts):
@@ −62 +61 @@
}
```
+- Use `createRouteMatcher()` when you need to protect multiple route groups or build complex matchers. The middleware supports both App and Pages routers (Clerk docs).
−- Use `createRouteMatcher()` when you need to protect multiple route groups or build complex matchers. The middleware supports App and Pages routers (Clerk docs).
+- By default, `clerkMiddleware()` does not protect routes — protection is opt-in. Prefer calling `auth()` inside App Router route handlers or server components for authoritative user context unless you need middleware redirects or proxying.
−- Prefer calling `auth()` inside App Router route handlers or server components for authoritative user context rather than making complex auth decisions fully in middleware, unless you need in-middleware redirects or proxying.
Reference: Clerk middleware docs (clerk.com/docs/reference/nextjs/clerk-middleware).
@@ −88 +87 @@
}
```
−### Step 3: Integrate Clerk tokens with Supabase RLS (required migration)
+### Step 3: Integrate Clerk tokens with Supabase RLS (migration and current recommended pattern)
+- Background: older public examples and community guides showed using `supabase.auth.setAuth` or Clerk-provided Supabase JWT templates to inject a Supabase-compatible token into the client. These approaches are no longer dependable: the supabase-js v2 client no longer exposes setAuth, and Clerk has shifted guidance toward server-side token provisioning and customized session claims (see sources below).
−- Clerk previously documented a "Supabase JWT template" approach. That template-based flow was deprecated by Clerk (deprecation noted in Clerk's Supabase integration guide). Migrate away from relying on pre-configured token templates.
+ - Evidence: supabase-js v2 issue reporting setAuth() missing (supabase/supabase#8490) and Clerk's session token customization docs.
+- Recommended pattern (server-mediated Authorization header):
+ - Ensure the client sends the user's Clerk session token in the Authorization: Bearer <token> header when making requests that need database access.
+ - On the server, create a Supabase client that forwards that Authorization header to Supabase so RLS policies can evaluate the token claims.
−- Recommended pattern: obtain a valid Clerk session token for the current user on the server and pass it as an Authorization: Bearer <token> header when creating the Supabase client. Do NOT expose a Supabase service_role key to the client (Clerk docs + Supabase docs).
+ - Do NOT expose a Supabase service_role key to any client — service_role bypasses RLS.
−Example (server-side):
+Example (server-side request handler that forwards client's bearer token to Supabase client):
```typescript
−import { auth } from '@clerk/nextjs/server';
import { createClient } from '@supabase/supabase-js';
+export async function handler(req) {
+ const authHeader = req.headers.get('authorization') || '';
+ if (!authHeader.startsWith('Bearer ')) {
+ return new Response(JSON.stringify({ error: 'Missing token' }), { status: 401 });
−export async function getAuthenticatedSupabase() {
+ }
− const { getToken } = await auth();