Clerk Authentication Patterns
Quick Guide: Clerk provides managed authentication with pre-built UI components, server-side helpers, and organization-based multi-tenancy. UseclerkMiddleware()for route protection,<Show>for conditional rendering, hooks for client state, andauth()/currentUser()for server-side auth. Clerk Core 3 (2026) replaces<SignedIn>/<SignedOut>with<Show>, renames the middleware file toproxy.ts(Next.js 16+), and consolidates packages.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
(You MUST use @clerk/nextjs/server for ALL server-side imports -- NEVER import server helpers from @clerk/nextjs)
(You MUST verify webhooks using Clerk's verifyWebhook helper -- NEVER trust unverified webhook payloads)
(You MUST use <Show> component instead of deprecated <SignedIn>/<SignedOut>/<Protect> -- these are removed in Core 3)
(You MUST NOT pass the full currentUser() object to the client -- it contains privateMetadata that must stay server-side)
(You MUST protect routes in BOTH middleware AND data access layer -- middleware alone is insufficient)
</critical_requirements>
Auto-detection: Clerk, ClerkProvider, clerkMiddleware, @clerk/nextjs, useUser, useAuth, useClerk, useSession, useOrganization, SignIn, SignUp, UserButton, UserProfile, OrganizationSwitcher, auth(), currentUser(), CLERK_SECRET_KEY, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, Show when="signed-in"
When to use:
- Adding authentication and user management to an application
- Building multi-tenant B2B apps with organization-based access control
- Using pre-built sign-in/sign-up UI components with customizable theming
- Protecting routes with middleware and server-side authorization checks
- Syncing Clerk user data to your database via webhooks
Key patterns covered:
- ClerkProvider setup, environment variables, middleware configuration
- Pre-built UI components (
<SignIn>,<SignUp>,<UserButton>,<Show>) - Client-side hooks (
useUser,useAuth,useSession,useOrganization) - Server-side auth (
auth(),currentUser()) in Server Components, Route Handlers, Server Actions - Middleware route protection with
clerkMiddleware()andcreateRouteMatcher() - Organization-based multi-tenancy with roles and permissions
- Webhook handling with Svix signature verification
When NOT to use:
- Self-hosted auth requirement (need full control over auth data storage)
- Cannot use a third-party auth service (compliance/regulatory constraints)
- Simple API key authentication (custom middleware is sufficient)
- Budget constraints prevent using a managed service
Detailed Resources:
- [reference.md](reference.md) - Decision frameworks, hooks quick reference, Core 3 migration cheat sheet
- [examples/core.md](examples/core.md) - ClerkProvider, environment variables, middleware configuration
- [examples/components.md](examples/components.md) - Pre-built components, customization, appearance prop
- [examples/hooks.md](examples/hooks.md) - useUser, useAuth, useSession, loading states, conditional rendering
- [examples/server.md](examples/server.md) - Server Components, API routes, Server Actions, webhook handling
- [examples/organizations.md](examples/organizations.md) - Organization management, roles, permissions, RBAC
<philosophy>
Philosophy
Clerk is a managed authentication platform that handles the entire auth lifecycle: sign-up, sign-in, session management, user profiles, organizations, and MFA. Instead of building auth from scratch, you integrate Clerk's SDK and pre-built components.
Core principles:
- Defense in depth -- Protect routes at the middleware layer AND verify auth at every data access point. Middleware alone is insufficient (CVE-2025-29927 demonstrated middleware bypass vulnerabilities).
- Server-first auth -- Use
auth()andcurrentUser()in Server Components and Route Handlers. Only use client hooks (useUser,useAuth) when you need reactive client-side state. - Pre-built over custom -- Use Clerk's
<SignIn>,<SignUp>,<UserButton>components. Only build custom flows when the pre-built components genuinely cannot meet requirements. - Organizations for multi-tenancy -- Use Clerk Organizations with roles and permissions for B2B apps. Do not build custom tenant systems on top of Clerk's user model.
- Webhook-driven sync -- Sync Clerk data to your database via webhooks, not by polling. Always verify webhook signatures with
verifyWebhook.
When to use Clerk:
- You need auth quickly with minimal custom code
- You want pre-built UI components for sign-in/sign-up/user management
- You need organization-based multi-tenancy with RBAC
- You want managed MFA, SSO (SAML/OIDC), and social login
When NOT to use Clerk:
- You need full control over auth data storage (self-hosted requirement)
- You cannot use a third-party auth service (compliance/regulatory)
- Your app only needs simple API key authentication
- Budget constraints prevent using a managed service
</philosophy>
<patterns>
Core Patterns
Pattern 1: ClerkProvider and Middleware Setup
Every Clerk app needs <ClerkProvider> wrapping the app and clerkMiddleware() protecting routes. See [examples/core.md](examples/core.md) for full setup examples.
Key rules:
ClerkProvidergoes inside<body>, not wrapping<html>-- Core 3 requires this- Use
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYenv var, never hardcode keys - Middleware file is
proxy.tson Next.js 16+ ormiddleware.tson Next.js <=15 - Webhook endpoint must be in the public routes list (verified separately by
verifyWebhook) CLERK_WEBHOOK_SIGNING_SECRETis the env var for webhook signing (notCLERK_WEBHOOK_SECRET)
// proxy.ts (Next.js 16+) or middleware.ts (Next.js <=15)
const isPublicRoute = createRouteMatcher([
"/",
"/sign-in(.*)",
"/sign-up(.*)",
"/api/webhooks(.*)",
]);
export default clerkMiddleware(async (auth, req) => {
if (!isPublicRoute(req)) {
await auth.protect();
}
});
Why good: Public routes explicitly whitelisted, everything else requires auth, webhook endpoint is public (verified separately)
// BAD: clerkMiddleware() with no callback
export default clerkMiddleware(); // All routes are PUBLIC by default!
Why bad: clerkMiddleware() without callback attaches auth data but does not protect any route
Pattern 2: Pre-Built UI Components and <Show>
Use <Show> for conditional rendering (Core 3 replacement for <SignedIn>/<SignedOut>/<Protect>). See [examples/components.md](examples/components.md) for full examples.
<Show when="signed-out"><SignInButton /></Show>
<Show when="signed-in"><UserButton /></Show>
<Show when={{ role: "org:admin" }}><AdminPanel /></Show>
<Show when={(has) => has({ permission: "org:invoices:manage" })}><InvoiceManager /></Show>
Why good: <Show> is the Core 3 API, supports string/object/callback conditions, fallback prop for unauthorized
// BAD: Deprecated -- removed in Core 3
<SignedIn>...</SignedIn>
<SignedOut>...</SignedOut>
<Protect role="admin">...</Protect>
Why bad: <SignedIn>, <SignedOut>, <Protect> removed in Core 3, use <Show> with when prop
Sign-in/sign-up pages require catch-all route segments [[...sign-in]] for multi-step flows (MFA, OAuth callbacks).
Pattern 3: Client-Side Hooks
Use hooks in Client Components for reactive auth state. Always check isLoaded before accessing data. See [examples/hooks.md](examples/hooks.md) for complete examples.
"use client";
const { isLoaded, isSignedIn, user } = useUser();
if (!isLoaded) return <div>Loading...</div>;
if (!isSignedIn) return <div>Please sign in</div>;
// Now safe to access user.firstNam