Clerk
Build with Clerk for authentication and user management. Use this skill when the project needs to integrate Clerk for sign-up, sign-in, OAuth, MFA, session management, organization multi-tenancy, webhooks, or pre-built UI components. Covers the Clerk React SDK, Next.js middleware, server-side auth, webhooks, organizations, and custom flows.
You are an auth specialist who integrates Clerk into projects. Clerk is a complete authentication and user management platform with pre-built UI components, multi-tenancy via organizations, and deep framework integrations for Next.js, React, and other platforms. ## Key Points - Use middleware for route protection — don't check auth in every page - Sync users to your database via webhooks — Clerk is the auth source, your DB is the app data source - Use organizations for multi-tenant apps — don't build tenancy yourself - Use `<SignedIn>` and `<SignedOut>` for conditional UI — cleaner than manual checks - Use JWT templates to pass Clerk auth to external services (Supabase, Hasura) - Set `afterSignOutUrl` on `<UserButton>` to control redirect behavior - Storing passwords or auth state in your own database — let Clerk handle it - Not setting up webhooks — your database won't know about new users - Checking auth in every component instead of using middleware - Exposing `CLERK_SECRET_KEY` to the client — it's server-only - Not handling the loading state from `useUser()` — `user` is null while loading - Building custom org/team logic when Clerk organizations would work ## Quick Example ```bash npm install @clerk/nextjs ``` ```env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up ```
skilldb get auth-services-skills/clerkFull skill: 275 linesClerk Authentication Integration
You are an auth specialist who integrates Clerk into projects. Clerk is a complete authentication and user management platform with pre-built UI components, multi-tenancy via organizations, and deep framework integrations for Next.js, React, and other platforms.
Core Philosophy
Drop-in UI, full control when needed
Clerk provides pre-built <SignIn>, <SignUp>, and <UserButton> components that
work out of the box. When you need custom flows, the same API powers headless
authentication with full control over every step.
Middleware-first in Next.js
Clerk's Next.js integration uses middleware to protect routes. Define which routes are public and which require auth — the middleware handles the rest. No wrapping components in providers or checking session state manually.
Organizations = multi-tenancy
Clerk's organizations feature gives you team/workspace multi-tenancy built in. Users can belong to multiple orgs, have roles, and switch between them. You don't build this yourself.
Setup
Install (Next.js)
npm install @clerk/nextjs
Environment variables
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
Provider (layout.tsx)
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}
Middleware (protect routes)
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isPublicRoute = createRouteMatcher([
'/',
'/sign-in(.*)',
'/sign-up(.*)',
'/api/webhooks(.*)',
]);
export default clerkMiddleware(async (auth, request) => {
if (!isPublicRoute(request)) {
await auth.protect();
}
});
export const config = {
matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};
Key Techniques
Pre-built components
import { SignIn, SignUp, UserButton, SignedIn, SignedOut } from '@clerk/nextjs';
// Sign-in page
export default function SignInPage() {
return <SignIn />;
}
// Sign-up page
export default function SignUpPage() {
return <SignUp />;
}
// Conditional rendering
function Header() {
return (
<nav>
<SignedIn>
<UserButton afterSignOutUrl="/" />
</SignedIn>
<SignedOut>
<a href="/sign-in">Sign in</a>
</SignedOut>
</nav>
);
}
Server-side auth (App Router)
import { auth, currentUser } from '@clerk/nextjs/server';
// Get auth state
export default async function DashboardPage() {
const { userId } = await auth();
if (!userId) redirect('/sign-in');
const user = await currentUser();
return <div>Hello {user?.firstName}</div>;
}
// In API routes
import { auth } from '@clerk/nextjs/server';
export async function GET() {
const { userId } = await auth();
if (!userId) return new Response('Unauthorized', { status: 401 });
const data = await db.query.posts.findMany({
where: eq(posts.authorId, userId),
});
return Response.json(data);
}
Client-side hooks
'use client';
import { useUser, useAuth, useClerk, useSignIn } from '@clerk/nextjs';
function Profile() {
const { user, isLoaded } = useUser();
const { userId, sessionId, getToken } = useAuth();
const { signOut } = useClerk();
if (!isLoaded) return <div>Loading...</div>;
return (
<div>
<p>{user?.emailAddresses[0].emailAddress}</p>
<button onClick={() => signOut()}>Sign out</button>
</div>
);
}
Organizations (multi-tenancy)
import { auth } from '@clerk/nextjs/server';
export async function GET() {
const { userId, orgId, orgRole } = await auth();
if (!orgId) return new Response('No org selected', { status: 400 });
// Query scoped to organization
const data = await db.query.projects.findMany({
where: eq(projects.orgId, orgId),
});
return Response.json(data);
}
// Client-side org switcher
import { OrganizationSwitcher } from '@clerk/nextjs';
function Nav() {
return <OrganizationSwitcher />;
}
Webhooks (sync users to database)
// app/api/webhooks/clerk/route.ts
import { Webhook } from 'svix';
import { headers } from 'next/headers';
import type { WebhookEvent } from '@clerk/nextjs/server';
export async function POST(req: Request) {
const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET!;
const headerPayload = await headers();
const svix_id = headerPayload.get('svix-id')!;
const svix_timestamp = headerPayload.get('svix-timestamp')!;
const svix_signature = headerPayload.get('svix-signature')!;
const payload = await req.json();
const body = JSON.stringify(payload);
const wh = new Webhook(WEBHOOK_SECRET);
let event: WebhookEvent;
try {
event = wh.verify(body, {
'svix-id': svix_id,
'svix-timestamp': svix_timestamp,
'svix-signature': svix_signature,
}) as WebhookEvent;
} catch {
return new Response('Invalid signature', { status: 400 });
}
switch (event.type) {
case 'user.created':
await db.insert(users).values({
id: event.data.id,
email: event.data.email_addresses[0]?.email_address,
name: `${event.data.first_name} ${event.data.last_name}`.trim(),
});
break;
case 'user.updated':
await db.update(users).set({
email: event.data.email_addresses[0]?.email_address,
name: `${event.data.first_name} ${event.data.last_name}`.trim(),
}).where(eq(users.id, event.data.id));
break;
case 'user.deleted':
await db.delete(users).where(eq(users.id, event.data.id!));
break;
}
return new Response('OK', { status: 200 });
}
JWT templates (custom claims)
// Get a custom JWT for external services
const { getToken } = useAuth();
const token = await getToken({ template: 'supabase' });
// Use with Supabase
const supabase = createClient(url, anonKey, {
global: { headers: { Authorization: `Bearer ${token}` } },
});
Best Practices
- Use middleware for route protection — don't check auth in every page
- Sync users to your database via webhooks — Clerk is the auth source, your DB is the app data source
- Use organizations for multi-tenant apps — don't build tenancy yourself
- Use
<SignedIn>and<SignedOut>for conditional UI — cleaner than manual checks - Use JWT templates to pass Clerk auth to external services (Supabase, Hasura)
- Set
afterSignOutUrlon<UserButton>to control redirect behavior
Anti-Patterns
- Storing passwords or auth state in your own database — let Clerk handle it
- Not setting up webhooks — your database won't know about new users
- Checking auth in every component instead of using middleware
- Exposing
CLERK_SECRET_KEYto the client — it's server-only - Not handling the loading state from
useUser()—useris null while loading - Building custom org/team logic when Clerk organizations would work
Install this skill directly: skilldb add auth-services-skills
Related Skills
Cognito
Build with Amazon Cognito for authentication and user management. Use this skill when the project needs User Pools for sign-up/sign-in, Identity Pools for AWS resource access, OAuth/OIDC federation, hosted UI or custom auth flows, token handling, or API Gateway integration. Covers the AWS Amplify Auth library, direct Cognito SDK usage, and securing backend APIs with Cognito tokens.
Descope
Integrate Descope to add secure, no-code/low-code authentication and user management to your applications. Use this skill when you need to quickly implement modern authentication methods like passkeys, magic links, social logins, and SSO, with minimal development effort and robust security out-of-the-box.
Firebase Auth
Build with Firebase Authentication for user sign-in. Use this skill when the project needs to integrate Firebase Auth for email/password, Google, GitHub, Apple, phone OTP, anonymous auth, custom tokens, or ID token verification. Covers the Firebase Auth SDK (v9+), providers, auth state, custom claims, and server-side verification.
Hanko
Integrate Hanko for modern, passwordless authentication in your web applications. Use Hanko to leverage passkeys (FIDO2), magic links, and email OTP for strong, developer-friendly auth experiences. This skill covers embedding Hanko's UI, handling authentication events, and server-side token verification.
Kinde
Build with Kinde for authentication and user management. Use this skill when the project needs to integrate Kinde for sign-up, sign-in, OAuth, feature flags, organizations, roles and permissions, or a developer-friendly auth platform with generous free tier. Covers the Kinde Next.js SDK, server/client auth, organizations, feature flags, and webhooks.
Logto
Logto is an open-source, managed identity service that simplifies authentication and authorization for your applications. Use Logto when you need a robust, scalable, and developer-friendly solution for user management, single sign-on (SSO), and API protection, supporting OIDC and OAuth 2.0.