Production authentication patterns for web applications using Clerk as the primary provider, with Auth0 and generic OAuth 2.0 as alternatives. Covers JWT verification, session management, RBAC, Supabase row-level security integration, multi-tenant access control, and middleware-driven auth enforcement.
When to use
Adding authentication to a Next.js application
Implementing role-based access control (RBAC) for API routes
Integrating Clerk with Supabase for row-level security
Building multi-tenant applications with organization-scoped access
Setting up OAuth 2.0 flows with third-party providers
Protecting API routes with JWT verification
When NOT to use
Machine-to-machine auth without user context — use API keys or mTLS instead
Embedded device authentication — use device-specific protocols
General API hardening (use `api-security` instead)
```sql
-- Supabase JWT function to extract Clerk user ID
CREATE OR REPLACE FUNCTION auth.clerk_user_id()
RETURNS TEXT AS $$
SELECT coalesce(
current_setting('request.jwt.claims', true)::json->>'sub',
(current_setting('request.jwt.claims', true)::json->>'userId')::text
);
$$ LANGUAGE sql STABLE;
-- RLS policy using Clerk user ID
CREATE POLICY "users_own_data" ON public.user_profiles
FOR ALL USING (clerk_user_id = auth.clerk_user_id());
```
Step 4: Implement RBAC with organization roles
```typescript
import { auth } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";
type OrgRole = "org:admin" | "org:member" | "org:viewer";
```sql
-- Organization-scoped access
CREATE POLICY "org_members_access" ON public.projects
FOR ALL USING (
org_id IN (
SELECT org_id FROM public.org_memberships
WHERE clerk_user_id = auth.clerk_user_id()
)
);
-- Admin-only write access within org
CREATE POLICY "org_admins_write" ON public.org_settings
FOR UPDATE USING (
EXISTS (
SELECT 1 FROM public.org_memberships
WHERE org_memberships.org_id = org_settings.org_id
AND org_memberships.clerk_user_id = auth.clerk_user_id()
AND org_memberships.role = 'admin'
)
);
```
Decision tree
New Next.js app → use Clerk with middleware-based auth
Enterprise SSO requirement → use Clerk Organizations or Auth0
Supabase data access → integrate Clerk JWT with RLS policies
Public API → use API keys with rate limiting, not session auth
Webhook from Clerk → verify svix signature before processing
Multi-tenant app → use Clerk Organizations with org-scoped RLS
Server component data fetch → use `auth()` to get user context
If unsure about auth provider → start with Clerk for fastest iteration
Edge cases and gotchas
Clerk token template mismatch — the Supabase JWT template must include the `sub` claim. Verify the template in Clerk Dashboard → JWT Templates.
Middleware matcher too broad — matching `/(.*)` intercepts static assets and causes performance issues. Use the recommended matcher pattern.
Organization role caching — Clerk caches org roles in the session token. Role changes may not reflect until the token refreshes (default: 60s).
Webhook replay — svix handles deduplication via `svix-id`, but your handler must be idempotent for retries.
RLS with service role key — the Supabase service role key bypasses RLS entirely. Never expose it to the client; use the anon key with user JWTs.
Auth in server actions — `auth()` works in server components and route handlers but needs `await` in Next.js 15+.
Cross-origin auth — Clerk sessions are domain-scoped. Multi-domain setups need satellite domains or custom auth forwarding.
Evaluation criteria
Middleware protects all non-public routes
API routes verify `userId` before processing requests
RBAC checks use role hierarchy, not string equality
Supabase RLS policies reference the Clerk JWT user ID
Webhook endpoint verifies svix signature before processing
No auth tokens stored in localStorage (HTTP-only cookies only)
Organization-scoped queries filter by `orgId` from the auth context
Error responses distinguish 401 (unauthenticated) from 403 (unauthorized)
Auth state is not duplicated between Clerk and application database
Token refresh and session expiry are handled gracefully in the UI
Research-backed changes
The biggest delta is Authentication. Fold the concrete changes into the operating notes, then discard the fluff.
Check Clerk changelog for SDK changes, middleware patterns, and organization-feature updates. Scan OWASP for session-management and JWT security advisories. Monitor Supabase for RLS and auth-hook changes. Update auth-flow diagrams and token-handling patterns.
Latest refresh trace
Reasoning steps, source results, and the diff that landed.
Apr 11, 2026 · 9:29 AM
triggerAutomation
editoropenai/gpt-5-mini
duration165.9s
statussuccess
web searches4
Revision: v7
This update clarifies Clerk session customization (preview feature and cookie size limits), removes reliance on deprecated supabase-js client patterns (setAuth), and replaces the Supabase-token-template guidance with a server-forwarding Authorization header pattern. It also tightens middleware and RLS guidance and cites Clerk changelog/docs and the supabase-js issue for verifiability.
Added Clerk Preview Custom Session Claims guidance; documented cookie-size constraint for custom claims; replaced Supabase token-template/code with Authorization header pattern; added citation to supabase-js v2 setAuth removal; clarified middleware filename note and opt-in protection behavior; preserved OWASP and supply-chain notes.
### Step 1: Set up Clerk Middleware (recommended current pattern)
−- Clerk's middleware integrates with Next.js via a proxy file. For Next.js ≤15nameit`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 codeisidentical;onlythefilenamediffers (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()`whenyouneedtoprotectmultiple route groups or buildcomplexmatchers.ThemiddlewaresupportsAppandPagesrouters(Clerkdocs).
+- By default, `clerkMiddleware()` does not protect routes — protectionisopt-in.Prefercalling`auth()`insideAppRouter route handlers or servercomponentsforauthoritativeusercontextunlessyouneedmiddlewareredirectsorproxying.
−- 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.
−### Step 3: Integrate Clerk tokens with Supabase RLS (requiredmigration)
+### Step 3: Integrate Clerk tokens with Supabase RLS (migration and currentrecommendedpattern)
+- 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).
−- Clerkpreviouslydocumenteda"SupabaseJWTtemplate"approach.That template-based flow was deprecated by Clerk (deprecation noted in Clerk's Supabaseintegrationguide).Migrate away from relying on pre-configured token templates.
+ - 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 (Clerkdocs+Supabase docs).
+- Do NOT expose a Supabase service_role key to any client —service_rolebypassesRLS.
−Example (server-side):
+Example (server-side request handler that forwards client's bearer token to Supabaseclient):
```typescript
−import { auth } from '@clerk/nextjs/server';
import { createClient } from '@supabase/supabase-js';
−export async function getAuthenticatedSupabase() {
+ }
− const { getToken } = await auth();
Research engine
Clerk Auth Patterns now treats its source set as a research system: canonical feeds for concrete deltas, index-like sources for discovery, and query hints for ranking.
Clerk Auth Patterns has unusually strong source quality and broad utility, so it deserves prominent placement.
Discovery process
1. Track canonical signals
Monitor 4 feed-like sources for release notes, changelog entries, and durable upstream deltas.
2. Discover net-new docs and leads
Scan 1 discovery-oriented sources such as docs indexes and sitemaps, then rank extracted links against explicit query hints instead of trusting nav order.
3. Transplant from trusted upstreams
Keep the skill grounded in trusted source deltas even when there is no direct upstream skill pack to transplant from.
4. Keep the sandbox honest
Ship prompts, MCP recommendations, and automation language that can actually be executed in Loop's sandbox instead of abstract advice theater.
Summary: Clerk Auth Patterns agent run was interrupted: Free credits temporarily have rate limits in place due to abuse. We are working on a resolution. Try again later, or pay for credits which continue to have unrestricted access. Pur
What changed: Agent crashed mid-run after 0 search(es). (agent error: Free credits temporarily have rate limits in place due to abuse. We are working on a resolution. Try again later, or pay for credits which continue to have unrestricted access. Purchase credits at htt)
Body changed: no
Update history3▶
Apr 5, 20264 sources
Clerk Auth Patterns agent run was interrupted: Free credits temporarily have rate limits in place due to abuse. We are working on a resolution. Try again later, or pay for credits which continue to have unrestricted access. Pur
Apr 3, 20264 sources
Clerk Auth Patterns agent run was interrupted: Free credits temporarily have rate limits in place due to abuse. We are working on a resolution. Try again later, or pay for credits which continue to have unrestricted access. Pur
Apr 1, 20264 sources
Clerk Auth Patterns now tracks Authentication and 3 other fresh signals.