> clerk-auth
Add authentication to web apps with Clerk — social login, email/password, magic links, organizations, RBAC, session management, webhooks, and multi-framework support. Use when tasks involve user authentication, team/org management, role-based access control, or integrating auth into Next.js, React, Remix, or Express applications.
curl "https://skillshub.wtf/TerminalSkills/skills/clerk-auth?format=md"Clerk Authentication
Drop-in authentication for modern web apps. Handles login UI, social providers, session management, organizations, and RBAC.
Setup (Next.js)
npm install @clerk/nextjs
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
CLERK_SECRET_KEY=sk_live_...
// app/layout.tsx — Wrap app in ClerkProvider
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider>
<html><body>{children}</body></html>
</ClerkProvider>
);
}
Middleware (Route Protection)
// middleware.ts — Protect routes at the edge
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isPublicRoute = createRouteMatcher([
'/',
'/pricing',
'/sign-in(.*)',
'/sign-up(.*)',
'/api/webhooks(.*)',
]);
export default clerkMiddleware(async (auth, req) => {
if (!isPublicRoute(req)) {
await auth.protect();
}
});
export const config = {
matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};
Server-Side Auth
Server Components (App Router)
import { auth, currentUser } from '@clerk/nextjs/server';
export default async function Page() {
// Quick access to IDs and role
const { userId, orgId, orgRole } = await auth();
// Full user object when needed
const user = await currentUser();
return <p>Hello {user?.firstName}</p>;
}
API Routes
import { auth } from '@clerk/nextjs/server';
import { NextResponse } from 'next/server';
export async function GET() {
const { userId, orgId } = await auth();
if (!userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// ... fetch data scoped to orgId
}
Server Actions
'use server';
import { auth } from '@clerk/nextjs/server';
export async function createProject(name: string) {
const { userId, orgId, orgRole } = await auth();
if (!orgId || (orgRole !== 'org:admin' && orgRole !== 'org:owner')) {
throw new Error('Forbidden');
}
return db.projects.create({ data: { name, orgId, createdBy: userId } });
}
Client-Side Auth
'use client';
import { useAuth, useUser, useOrganization } from '@clerk/nextjs';
export function ProfileCard() {
const { isSignedIn, userId } = useAuth();
const { user } = useUser();
const { organization, membership } = useOrganization();
if (!isSignedIn) return <p>Not signed in</p>;
return (
<div>
<p>{user?.fullName}</p>
<p>Org: {organization?.name}</p>
<p>Role: {membership?.role}</p>
</div>
);
}
Pre-Built Components
import {
SignIn, // Full sign-in page
SignUp, // Full sign-up page
UserButton, // Avatar dropdown (profile, sign out)
UserProfile, // Full profile management page
OrganizationSwitcher, // Org dropdown + create org
OrganizationList, // List orgs + join/create
OrganizationProfile, // Org settings (members, roles)
} from '@clerk/nextjs';
// Sign-in page
// app/sign-in/[[...sign-in]]/page.tsx
export default function SignInPage() {
return <SignIn />;
}
// Header with org switcher and user menu
export function Header() {
return (
<nav>
<OrganizationSwitcher hidePersonal={true} />
<UserButton afterSignOutUrl="/" />
</nav>
);
}
Organizations (Multi-Tenant)
Enable at dashboard.clerk.com → Organizations.
Create Organization
import { auth, clerkClient } from '@clerk/nextjs/server';
async function createOrg(name: string) {
const { userId } = await auth();
const client = await clerkClient();
return client.organizations.createOrganization({
name,
createdBy: userId!,
});
}
Invite Members
async function inviteMember(orgId: string, email: string, role: string) {
const client = await clerkClient();
return client.organizations.createOrganizationInvitation({
organizationId: orgId,
emailAddress: email,
role, // 'org:admin', 'org:member', or custom roles
inviterUserId: (await auth()).userId!,
});
}
Custom Roles
Define at dashboard.clerk.com → Organizations → Roles:
org:owner — Full access, can delete org
org:admin — Manage members, settings
org:member — Standard access
org:viewer — Read-only (custom)
org:billing — Billing management only (custom)
Check roles in code:
const { orgRole, has } = await auth();
// Direct role check
if (orgRole === 'org:admin') { ... }
// Permission-based check (preferred — decouples code from role names)
if (has({ permission: 'org:projects:manage' })) { ... }
Webhooks
Sync Clerk events to your database:
// app/api/webhooks/clerk/route.ts
import { Webhook } from 'svix';
import { WebhookEvent } from '@clerk/nextjs/server';
export async function POST(req: Request) {
const wh = new Webhook(process.env.CLERK_WEBHOOK_SECRET!);
const body = await req.text();
const svixHeaders = {
'svix-id': req.headers.get('svix-id')!,
'svix-timestamp': req.headers.get('svix-timestamp')!,
'svix-signature': req.headers.get('svix-signature')!,
};
const event = wh.verify(body, svixHeaders) as WebhookEvent;
switch (event.type) {
case 'user.created':
await db.users.create({ data: {
clerkId: event.data.id,
email: event.data.email_addresses[0]?.email_address,
name: `${event.data.first_name} ${event.data.last_name}`.trim(),
}});
break;
case 'user.deleted':
await db.users.delete({ where: { clerkId: event.data.id } });
break;
case 'organization.created':
await db.orgs.create({ data: {
clerkOrgId: event.data.id,
name: event.data.name,
slug: event.data.slug,
}});
break;
}
return new Response('OK');
}
Key events: user.created, user.updated, user.deleted, organization.created, organization.updated, organizationMembership.created, organizationMembership.deleted.
JWT Templates (API Auth)
For external APIs or microservices that need to verify Clerk tokens:
// Configure at dashboard.clerk.com → JWT Templates
// Template name: "api-token"
// Claims: { "userId": "{{user.id}}", "orgId": "{{org.id}}", "role": "{{org.role}}" }
// Client: get a custom JWT
const { getToken } = useAuth();
const token = await getToken({ template: 'api-token' });
// External API: verify the JWT
import { createClerkClient } from '@clerk/backend';
const clerk = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY });
async function verifyRequest(req: Request) {
const token = req.headers.get('Authorization')?.replace('Bearer ', '');
if (!token) throw new Error('No token');
return clerk.verifyToken(token);
}
Express.js
import { ClerkExpressRequireAuth } from '@clerk/clerk-sdk-node';
// Protect routes
app.use('/api', ClerkExpressRequireAuth());
app.get('/api/me', (req, res) => {
res.json({ userId: req.auth.userId, orgId: req.auth.orgId });
});
Guidelines
- Middleware is the primary protection layer — don't rely on component-level checks alone. Middleware runs at the edge before any page code.
- Use
auth()in server components, notuseAuth()— server-side checks can't be bypassed by the client - Webhook signature verification is mandatory — use
svixlibrary to verify every webhook payload - Sync to your database via webhooks — don't query Clerk's API for every database operation. Keep a local copy of users and orgs.
- Use organizations for B2B — even if you think you only need simple auth now. Adding multi-tenancy later is much harder than starting with it.
- Permission-based checks over role checks —
has({ permission: 'X' })is more maintainable thanrole === 'org:admin' hidePersonal={true}for B2B apps — personal workspaces confuse users in team-based products- Configure sign-in/up URLs in env vars — Clerk uses these for redirects after auth flows
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.