← Back to list

clerk-auth
by phrazzld
⭐ 2🍴 1📅 Jan 24, 2026
SKILL.md
name: clerk-auth description: "Clerk authentication integration patterns for Next.js and Convex. Invoke for: user authentication, session management, JWT templates, webhook handling, middleware configuration, protected routes, Convex auth integration."
Clerk Authentication Patterns
Authentication integration patterns for Clerk with Next.js and Convex backends.
Core Concepts
Authentication Flow
- User authenticates via Clerk (sign-in/sign-up)
- Clerk issues session token (JWT)
- Frontend passes token to backend
- Backend verifies token and extracts user identity
Key Components
- Clerk Dashboard: User management, JWT templates, webhooks
- @clerk/nextjs: React hooks, middleware, components
- Convex auth:
ctx.auth.getUserIdentity()for backend verification
Next.js Setup
Middleware
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
const isPublicRoute = createRouteMatcher([
'/',
'/sign-in(.*)',
'/sign-up(.*)',
'/api/webhooks(.*)', // Webhooks must be public
])
export default clerkMiddleware((auth, req) => {
if (!isPublicRoute(req)) {
auth().protect()
}
})
export const config = {
matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
}
Environment Variables
# .env.local
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
CLERK_SECRET_KEY=sk_test_xxx
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
Critical: Set on BOTH Vercel and local. Mismatch causes silent failures.
Convex Integration
JWT Template (Clerk Dashboard)
Create JWT template named convex:
{
"sub": "{{user.id}}",
"iss": "https://clerk.your-domain.com",
"email": "{{user.primary_email_address}}",
"name": "{{user.full_name}}"
}
Template name is case-sensitive. Must match convex/auth.config.ts.
Convex Auth Config
// convex/auth.config.ts
export default {
providers: [
{
domain: process.env.CLERK_JWT_ISSUER_DOMAIN,
applicationID: "convex",
},
],
}
Backend User Identity
// convex/users.ts
import { query, mutation } from "./_generated/server"
export const getCurrentUser = query({
handler: async (ctx) => {
const identity = await ctx.auth.getUserIdentity()
if (!identity) return null
// identity contains JWT claims:
// - subject (Clerk user ID)
// - email
// - name
return identity
},
})
Webhook Handling
Webhook URL
Configure in Clerk Dashboard → Webhooks:
- URL:
https://your-app.com/api/webhooks/clerk - Events:
user.created,user.updated,user.deleted
Webhook Handler
// app/api/webhooks/clerk/route.ts
import { Webhook } from 'svix'
import { headers } from 'next/headers'
import { WebhookEvent } from '@clerk/nextjs/server'
export async function POST(req: Request) {
const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET
if (!WEBHOOK_SECRET) {
throw new Error('Missing CLERK_WEBHOOK_SECRET')
}
const headerPayload = headers()
const svix_id = headerPayload.get('svix-id')
const svix_timestamp = headerPayload.get('svix-timestamp')
const svix_signature = headerPayload.get('svix-signature')
if (!svix_id || !svix_timestamp || !svix_signature) {
return new Response('Missing svix headers', { status: 400 })
}
const payload = await req.json()
const body = JSON.stringify(payload)
const wh = new Webhook(WEBHOOK_SECRET)
let evt: WebhookEvent
try {
evt = wh.verify(body, {
'svix-id': svix_id,
'svix-timestamp': svix_timestamp,
'svix-signature': svix_signature,
}) as WebhookEvent
} catch (err) {
console.error('Webhook verification failed:', err)
return new Response('Invalid signature', { status: 400 })
}
// Handle events
switch (evt.type) {
case 'user.created':
// Sync user to database
break
case 'user.updated':
// Update user in database
break
case 'user.deleted':
// Handle user deletion
break
}
return new Response('OK', { status: 200 })
}
Common Issues
"Unauthenticated" errors
- Check JWT template name matches config
- Verify
CLERK_JWT_ISSUER_DOMAINis set - Ensure middleware isn't blocking auth routes
Webhook failures
- Verify
CLERK_WEBHOOK_SECRETis set (not just locally) - Check webhook URL uses canonical domain (no redirects)
- Ensure
/api/webhooks/*is in public routes
Session not persisting
- Check cookies are being set (dev tools)
- Verify domain configuration in Clerk Dashboard
- Ensure HTTPS in production
Best Practices
- Sync users via webhooks, not on-demand
- Store Clerk ID as foreign key in your database
- Use
currentUser()for server components - Use
useUser()for client components - Protect API routes with
auth()in route handlers - Keep JWT templates minimal (only needed claims)
References
references/convex-integration.md— Detailed Convex auth patternsreferences/webhook-events.md— Clerk webhook event typesreferences/troubleshooting.md— Common issues and solutions
Related Skills
billing-security— Payment and auth security patternsexternal-integration-patterns— General external service integrationenv-var-hygiene— Environment variable management
Score
Total Score
50/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon