{"id":"414ce2a3-fb87-49b0-9faf-e6c9d42a0f97","shortId":"3USDx5","kind":"skill","title":"clerk-auth","tagline":"Expert patterns for Clerk auth implementation, middleware,","description":"# Clerk Authentication\n\nExpert patterns for Clerk auth implementation, middleware, organizations, webhooks, and user sync\n\n## Patterns\n\n### Next.js App Router Setup\n\nComplete Clerk setup for Next.js 14/15 App Router.\n\nIncludes ClerkProvider, environment variables, and basic\nsign-in/sign-up components.\n\nKey components:\n- ClerkProvider: Wraps app for auth context\n- <SignIn />, <SignUp />: Pre-built auth forms\n- <UserButton />: User menu with session management\n\n### Code_example\n\n# Environment variables (.env.local)\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...\nCLERK_SECRET_KEY=sk_test_...\nNEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in\nNEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up\nNEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard\nNEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboarding\n\n// app/layout.tsx\nimport { ClerkProvider } from '@clerk/nextjs';\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <ClerkProvider>\n      <html lang=\"en\">\n        <body>{children}</body>\n      </html>\n    </ClerkProvider>\n  );\n}\n\n// app/sign-in/[[...sign-in]]/page.tsx\nimport { SignIn } from '@clerk/nextjs';\n\nexport default function SignInPage() {\n  return (\n    <div className=\"flex justify-center items-center min-h-screen\">\n      <SignIn />\n    </div>\n  );\n}\n\n// app/sign-up/[[...sign-up]]/page.tsx\nimport { SignUp } from '@clerk/nextjs';\n\nexport default function SignUpPage() {\n  return (\n    <div className=\"flex justify-center items-center min-h-screen\">\n      <SignUp />\n    </div>\n  );\n}\n\n// components/Header.tsx\nimport { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';\n\nexport function Header() {\n  return (\n    <header className=\"flex justify-between p-4\">\n      <h1>My App</h1>\n      <SignedOut>\n        <SignInButton />\n      </SignedOut>\n      <SignedIn>\n        <UserButton afterSignOutUrl=\"/\" />\n      </SignedIn>\n    </header>\n  );\n}\n\n### Anti_patterns\n\n- Pattern: ClerkProvider inside page component | Why: Provider must wrap entire app in root layout | Fix: Move ClerkProvider to app/layout.tsx\n- Pattern: Using auth() without middleware | Why: auth() requires clerkMiddleware to be configured | Fix: Set up middleware.ts with clerkMiddleware\n\n### References\n\n- https://clerk.com/docs/nextjs/getting-started/quickstart\n\n### Middleware Route Protection\n\nProtect routes using clerkMiddleware and createRouteMatcher.\n\nBest practices:\n- Single middleware.ts file at project root\n- Use createRouteMatcher for route groups\n- auth.protect() for explicit protection\n- Centralize all auth logic in middleware\n\n### Code_example\n\n// middleware.ts\nimport { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';\n\n// Define protected route patterns\nconst isProtectedRoute = createRouteMatcher([\n  '/dashboard(.*)',\n  '/settings(.*)',\n  '/api/private(.*)',\n]);\n\n// Define public routes (optional, for clarity)\nconst isPublicRoute = createRouteMatcher([\n  '/',\n  '/sign-in(.*)',\n  '/sign-up(.*)',\n  '/api/webhooks(.*)',\n]);\n\nexport default clerkMiddleware(async (auth, req) => {\n  // Protect matched routes\n  if (isProtectedRoute(req)) {\n    await auth.protect();\n  }\n});\n\nexport const config = {\n  matcher: [\n    // Match all routes except static files\n    '/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',\n    // Always run for API routes\n    '/(api|trpc)(.*)',\n  ],\n};\n\n// Advanced: Role-based protection\nexport default clerkMiddleware(async (auth, req) => {\n  if (isProtectedRoute(req)) {\n    await auth.protect();\n  }\n\n  // Admin routes require admin role\n  if (req.nextUrl.pathname.startsWith('/admin')) {\n    await auth.protect({\n      role: 'org:admin',\n    });\n  }\n\n  // Premium routes require premium permission\n  if (req.nextUrl.pathname.startsWith('/premium')) {\n    await auth.protect({\n      permission: 'org:premium:access',\n    });\n  }\n});\n\n### Anti_patterns\n\n- Pattern: Multiple middleware.ts files | Why: Causes conflicts and redirect loops | Fix: Use single middleware.ts with route matchers\n- Pattern: Manual redirects in components | Why: Double redirects, missed routes | Fix: Handle all redirects in middleware\n- Pattern: Missing matcher config | Why: Middleware won't run on all routes | Fix: Add comprehensive matcher pattern\n\n### References\n\n- https://clerk.com/docs/reference/nextjs/clerk-middleware\n\n### Server Component Authentication\n\nAccess auth state in Server Components using auth() and currentUser().\n\nKey functions:\n- auth(): Returns userId, sessionId, orgId, claims\n- currentUser(): Returns full User object\n- Both require clerkMiddleware to be configured\n\n### Code_example\n\n// app/dashboard/page.tsx (Server Component)\nimport { auth, currentUser } from '@clerk/nextjs/server';\nimport { redirect } from 'next/navigation';\n\nexport default async function DashboardPage() {\n  const { userId } = await auth();\n\n  if (!userId) {\n    redirect('/sign-in');\n  }\n\n  // Full user data (counts toward rate limits)\n  const user = await currentUser();\n\n  return (\n    <div>\n      <h1>Welcome, {user?.firstName}!</h1>\n      <p>Email: {user?.emailAddresses[0]?.emailAddress}</p>\n    </div>\n  );\n}\n\n// Using auth() for quick checks\nexport default async function ProtectedLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  const { userId, orgId, orgRole } = await auth();\n\n  if (!userId) {\n    redirect('/sign-in');\n  }\n\n  // Check organization access\n  if (!orgId) {\n    redirect('/select-org');\n  }\n\n  return (\n    <div>\n      <p>Organization Role: {orgRole}</p>\n      {children}\n    </div>\n  );\n}\n\n// Server Action with auth check\n// app/actions/posts.ts\n'use server';\nimport { auth } from '@clerk/nextjs/server';\n\nexport async function createPost(formData: FormData) {\n  const { userId } = await auth();\n\n  if (!userId) {\n    throw new Error('Unauthorized');\n  }\n\n  const title = formData.get('title') as string;\n\n  // Create post with userId\n  const post = await prisma.post.create({\n    data: {\n      title,\n      authorId: userId,\n    },\n  });\n\n  return post;\n}\n\n### Anti_patterns\n\n- Pattern: Not awaiting auth() | Why: auth() is async in App Router | Fix: Use await auth() or const { userId } = await auth()\n- Pattern: Using currentUser() for simple checks | Why: Counts toward rate limits, slower than auth() | Fix: Use auth() for userId checks, currentUser() for user data\n\n### References\n\n- https://clerk.com/docs/references/nextjs/auth\n\n### Client Component Hooks\n\nAccess auth state in Client Components using hooks.\n\nKey hooks:\n- useUser(): User object and loading state\n- useAuth(): Auth state, signOut, etc.\n- useSession(): Session object\n- useOrganization(): Current organization\n\n### Code_example\n\n// components/UserProfile.tsx\n'use client';\nimport { useUser, useAuth } from '@clerk/nextjs';\n\nexport function UserProfile() {\n  const { user, isLoaded, isSignedIn } = useUser();\n  const { signOut } = useAuth();\n\n  if (!isLoaded) {\n    return <div>Loading...</div>;\n  }\n\n  if (!isSignedIn) {\n    return <div>Not signed in</div>;\n  }\n\n  return (\n    <div>\n      <img src={user.imageUrl} alt={user.fullName ?? ''} />\n      <h2>{user.fullName}</h2>\n      <p>{user.emailAddresses[0]?.emailAddress}</p>\n      <button onClick={() => signOut()}>Sign Out</button>\n    </div>\n  );\n}\n\n// Organization context\n'use client';\nimport { useOrganization, useOrganizationList } from '@clerk/nextjs';\n\nexport function OrgSwitcher() {\n  const { organization, membership } = useOrganization();\n  const { setActive, userMemberships } = useOrganizationList({\n    userMemberships: { infinite: true },\n  });\n\n  if (!organization) {\n    return <p>No organization selected</p>;\n  }\n\n  return (\n    <div>\n      <p>Current: {organization.name}</p>\n      <p>Role: {membership?.role}</p>\n\n      <select\n        onChange={(e) => setActive?.({ organization: e.target.value })}\n        value={organization.id}\n      >\n        {userMemberships.data?.map((mem) => (\n          <option key={mem.organization.id} value={mem.organization.id}>\n            {mem.organization.name}\n          </option>\n        ))}\n      </select>\n    </div>\n  );\n}\n\n// Protected client component\n'use client';\nimport { useAuth } from '@clerk/nextjs';\nimport { useRouter } from 'next/navigation';\nimport { useEffect } from 'react';\n\nexport function ProtectedContent() {\n  const { isLoaded, userId } = useAuth();\n  const router = useRouter();\n\n  useEffect(() => {\n    if (isLoaded && !userId) {\n      router.push('/sign-in');\n    }\n  }, [isLoaded, userId, router]);\n\n  if (!isLoaded || !userId) {\n    return <div>Loading...</div>;\n  }\n\n  return <div>Protected content here</div>;\n}\n\n### Anti_patterns\n\n- Pattern: Not checking isLoaded | Why: Auth state undefined during hydration | Fix: Always check isLoaded before accessing user/auth state\n- Pattern: Using hooks in Server Components | Why: Hooks only work in Client Components | Fix: Use auth() and currentUser() in Server Components\n\n### References\n\n- https://clerk.com/docs/references/react/use-user\n\n### Organizations and Multi-Tenancy\n\nImplement B2B multi-tenancy with Clerk Organizations.\n\nFeatures:\n- Multiple orgs per user\n- Roles and permissions\n- Organization-scoped data\n- Enterprise SSO per organization\n\n### Code_example\n\n// Organization creation UI\n// app/create-org/page.tsx\nimport { CreateOrganization } from '@clerk/nextjs';\n\nexport default function CreateOrgPage() {\n  return (\n    <div className=\"flex justify-center\">\n      <CreateOrganization afterCreateOrganizationUrl=\"/dashboard\" />\n    </div>\n  );\n}\n\n// Organization profile and management\n// app/org-settings/page.tsx\nimport { OrganizationProfile } from '@clerk/nextjs';\n\nexport default function OrgSettingsPage() {\n  return <OrganizationProfile />;\n}\n\n// Organization switcher in header\n// components/Header.tsx\nimport { OrganizationSwitcher, UserButton } from '@clerk/nextjs';\n\nexport function Header() {\n  return (\n    <header className=\"flex justify-between p-4\">\n      <OrganizationSwitcher\n        hidePersonal\n        afterCreateOrganizationUrl=\"/dashboard\"\n        afterSelectOrganizationUrl=\"/dashboard\"\n      />\n      <UserButton />\n    </header>\n  );\n}\n\n// Org-scoped data access\n// app/dashboard/page.tsx\nimport { auth } from '@clerk/nextjs/server';\nimport { prisma } from '@/lib/prisma';\n\nexport default async function DashboardPage() {\n  const { orgId } = await auth();\n\n  if (!orgId) {\n    redirect('/select-org');\n  }\n\n  // Fetch org-scoped data\n  const projects = await prisma.project.findMany({\n    where: { organizationId: orgId },\n  });\n\n  return (\n    <div>\n      <h1>Projects</h1>\n      {projects.map((p) => (\n        <div key={p.id}>{p.name}</div>\n      ))}\n    </div>\n  );\n}\n\n// Role-based UI\n'use client';\nimport { useOrganization, Protect } from '@clerk/nextjs';\n\nexport function AdminPanel() {\n  const { membership } = useOrganization();\n\n  // Using Protect component\n  return (\n    <Protect role=\"org:admin\" fallback={<p>Admin access required</p>}>\n      <div>Admin content here</div>\n    </Protect>\n  );\n\n  // Or manual check\n  if (membership?.role !== 'org:admin') {\n    return <p>Admin access required</p>;\n  }\n\n  return <div>Admin content here</div>;\n}\n\n### Anti_patterns\n\n- Pattern: Not scoping data by orgId | Why: Data leaks between organizations | Fix: Always filter queries by orgId from auth()\n- Pattern: Hardcoding role strings | Why: Typos cause access issues | Fix: Define role constants or use TypeScript enums\n\n### References\n\n- https://clerk.com/docs/guides/organizations\n- https://clerk.com/articles/multi-tenancy-in-react-applications-guide\n\n### Webhook User Sync\n\nSync Clerk users to your database using webhooks.\n\nKey webhooks:\n- user.created: New user signed up\n- user.updated: User profile changed\n- user.deleted: User deleted account\n\nUses svix for signature verification.\n\n### Code_example\n\n// app/api/webhooks/clerk/route.ts\nimport { Webhook } from 'svix';\nimport { headers } from 'next/headers';\nimport { WebhookEvent } from '@clerk/nextjs/server';\nimport { prisma } from '@/lib/prisma';\n\nexport async function POST(req: Request) {\n  const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET;\n\n  if (!WEBHOOK_SECRET) {\n    throw new Error('Missing CLERK_WEBHOOK_SECRET');\n  }\n\n  // Get headers\n  const headerPayload = await headers();\n  const svix_id = headerPayload.get('svix-id');\n  const svix_timestamp = headerPayload.get('svix-timestamp');\n  const svix_signature = headerPayload.get('svix-signature');\n\n  if (!svix_id || !svix_timestamp || !svix_signature) {\n    return new Response('Missing svix headers', { status: 400 });\n  }\n\n  // Get body\n  const payload = await req.json();\n  const body = JSON.stringify(payload);\n\n  // Verify webhook\n  const wh = new Webhook(WEBHOOK_SECRET);\n  let evt: WebhookEvent;\n\n  try {\n    evt = wh.verify(body, {\n      'svix-id': svix_id,\n      'svix-timestamp': svix_timestamp,\n      'svix-signature': svix_signature,\n    }) as WebhookEvent;\n  } catch (err) {\n    console.error('Webhook verification failed:', err);\n    return new Response('Verification failed', { status: 400 });\n  }\n\n  // Handle events\n  const eventType = evt.type;\n\n  if (eventType === 'user.created') {\n    const { id, email_addresses, first_name, last_name, image_url } = evt.data;\n\n    await prisma.user.create({\n      data: {\n        clerkId: id,\n        email: email_addresses[0]?.email_address,\n        firstName: first_name,\n        lastName: last_name,\n        imageUrl: image_url,\n      },\n    });\n  }\n\n  if (eventType === 'user.updated') {\n    const { id, email_addresses, first_name, last_name, image_url } = evt.data;\n\n    await prisma.user.update({\n      where: { clerkId: id },\n      data: {\n        email: email_addresses[0]?.email_address,\n        firstName: first_name,\n        lastName: last_name,\n        imageUrl: image_url,\n      },\n    });\n  }\n\n  if (eventType === 'user.deleted') {\n    const { id } = evt.data;\n\n    await prisma.user.delete({\n      where: { clerkId: id! },\n    });\n  }\n\n  return new Response('Webhook processed', { status: 200 });\n}\n\n// Prisma schema\n// prisma/schema.prisma\nmodel User {\n  id        String   @id @default(cuid())\n  clerkId   String   @unique\n  email     String   @unique\n  firstName String?\n  lastName  String?\n  imageUrl  String?\n  createdAt DateTime @default(now())\n  updatedAt DateTime @updatedAt\n\n  posts     Post[]\n  @@index([clerkId])\n}\n\n### Anti_patterns\n\n- Pattern: Not verifying webhook signature | Why: Anyone can hit your endpoint with fake data | Fix: Always verify with svix\n- Pattern: Blocking middleware for webhook routes | Why: Webhooks come from Clerk, not authenticated users | Fix: Add /api/webhooks(.*)' to public routes\n- Pattern: Not handling race conditions | Why: user.created might arrive after user.updated | Fix: Use upsert instead of create, handle missing records\n\n### References\n\n- https://clerk.com/docs/webhooks/sync-data\n- https://clerk.com/articles/how-to-sync-clerk-user-data-to-your-database\n\n### API Route Protection\n\nProtect API routes using auth() from Clerk.\n\nRoute Handlers in App Router use auth() for authentication.\nMiddleware provides initial protection, auth() provides in-handler verification.\n\n### Code_example\n\n// app/api/projects/route.ts\nimport { auth } from '@clerk/nextjs/server';\nimport { prisma } from '@/lib/prisma';\nimport { NextResponse } from 'next/server';\n\nexport async function GET() {\n  const { userId, orgId } = await auth();\n\n  if (!userId) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  // User's personal projects or org projects\n  const projects = await prisma.project.findMany({\n    where: orgId\n      ? { organizationId: orgId }\n      : { userId, organizationId: null },\n  });\n\n  return NextResponse.json(projects);\n}\n\nexport async function POST(req: Request) {\n  const { userId, orgId } = await auth();\n\n  if (!userId) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  const body = await req.json();\n\n  const project = await prisma.project.create({\n    data: {\n      name: body.name,\n      userId,\n      organizationId: orgId ?? null,\n    },\n  });\n\n  return NextResponse.json(project, { status: 201 });\n}\n\n// Protected with role check\n// app/api/admin/users/route.ts\nexport async function GET() {\n  const { userId, orgRole } = await auth();\n\n  if (!userId) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  if (orgRole !== 'org:admin') {\n    return NextResponse.json({ error: 'Forbidden' }, { status: 403 });\n  }\n\n  // Admin-only logic\n  const users = await prisma.user.findMany();\n  return NextResponse.json(users);\n}\n\n// Using getAuth in older patterns (not recommended)\n// For backwards compatibility only\nimport { getAuth } from '@clerk/nextjs/server';\n\nexport async function GET(req: Request) {\n  const { userId } = getAuth(req);\n  // ...\n}\n\n### Anti_patterns\n\n- Pattern: Trusting middleware alone | Why: Middleware can be bypassed (CVE-2025-29927) | Fix: Always verify auth in route handler too\n- Pattern: Not checking orgId for multi-tenant | Why: Users might access other org's data | Fix: Always filter by orgId from auth()\n\n### References\n\n- https://clerk.com/docs/guides/protecting-pages\n\n## Sharp Edges\n\n### CVE-2025-29927 Middleware Bypass Vulnerability\n\nSeverity: CRITICAL\n\n### Multiple Middleware Files Cause Conflicts\n\nSeverity: HIGH\n\n### 4KB Session Token Cookie Limit\n\nSeverity: HIGH\n\n### auth() Requires clerkMiddleware Configuration\n\nSeverity: HIGH\n\n### Webhook Race Conditions\n\nSeverity: MEDIUM\n\n### auth() is Async in App Router\n\nSeverity: MEDIUM\n\n### Middleware Blocks Webhook Endpoints\n\nSeverity: MEDIUM\n\n### Accessing Auth State Before isLoaded\n\nSeverity: MEDIUM\n\n### Manual Redirects Cause Double Redirects\n\nSeverity: MEDIUM\n\n### Organization Data Not Scoped by orgId\n\nSeverity: HIGH\n\n## Validation Checks\n\n### Clerk Secret Key in Client Code\n\nSeverity: ERROR\n\nCLERK_SECRET_KEY must only be used server-side\n\nMessage: Clerk secret key exposed to client. Use CLERK_SECRET_KEY without NEXT_PUBLIC prefix.\n\n### Protected Route Without Middleware\n\nSeverity: ERROR\n\nAPI routes should have middleware protection\n\nMessage: API route without auth check. Add middleware protection or auth() check.\n\n### Hardcoded Clerk API Keys\n\nSeverity: ERROR\n\nClerk keys should use environment variables\n\nMessage: Hardcoded Clerk keys. Use environment variables.\n\n### Missing Await on auth()\n\nSeverity: ERROR\n\nauth() is async in App Router and must be awaited\n\nMessage: auth() not awaited. Use 'await auth()' in App Router.\n\n### Multiple Middleware Files\n\nSeverity: WARNING\n\nOnly one middleware.ts file should exist\n\nMessage: Multiple middleware files detected. Use single middleware.ts.\n\n### Webhook Route Not Excluded from Protection\n\nSeverity: WARNING\n\nWebhook routes should be public\n\nMessage: Webhook route may be blocked by middleware. Add to public routes.\n\n### Accessing Auth Without isLoaded Check\n\nSeverity: WARNING\n\nCheck isLoaded before accessing user state in client components\n\nMessage: Accessing user without isLoaded check. Check isLoaded first.\n\n### Clerk Hooks in Server Component\n\nSeverity: ERROR\n\nClerk hooks only work in Client Components\n\nMessage: Clerk hooks in Server Component. Add 'use client' or use auth().\n\n### Multi-Tenant Query Without orgId\n\nSeverity: WARNING\n\nOrganization data should be scoped by orgId\n\nMessage: Query without organization scope. Filter by orgId for multi-tenancy.\n\n### Webhook Without Signature Verification\n\nSeverity: ERROR\n\nClerk webhooks must verify svix signature\n\nMessage: Webhook without signature verification. Use svix to verify.\n\n## Collaboration\n\n### Delegation Triggers\n\n- user needs database -> postgres-wizard (User table with clerkId)\n- user needs payments -> stripe-integration (Customer linked to Clerk user)\n- user needs search -> algolia-search (Secured API keys per user)\n- user needs analytics -> segment-cdp (User identification)\n- user needs email -> resend-email (Transactional emails)\n\n## When to Use\n- User mentions or implies: adding authentication\n- User mentions or implies: clerk auth\n- User mentions or implies: user authentication\n- User mentions or implies: sign in\n- User mentions or implies: sign up\n- User mentions or implies: user management\n- User mentions or implies: multi-tenancy\n- User mentions or implies: organizations\n- User mentions or implies: sso\n- User mentions or implies: single sign-on\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["clerk","auth","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows"],"capabilities":["skill","source-sickn33","skill-clerk-auth","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/clerk-auth","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34882 github stars · SKILL.md body (20,643 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-24T12:50:46.648Z","embedding":null,"createdAt":"2026-04-18T21:34:27.298Z","updatedAt":"2026-04-24T12:50:46.648Z","lastSeenAt":"2026-04-24T12:50:46.648Z","tsv":"'-2025':1630,1670 '-29927':1631,1671 '/admin':348 '/api/private':262 '/api/webhooks':274,1398 '/articles/how-to-sync-clerk-user-data-to-your-database':1428 '/articles/multi-tenancy-in-react-applications-guide':1065 '/dashboard':105,260 '/docs/guides/organizations':1062 '/docs/guides/protecting-pages':1666 '/docs/nextjs/getting-started/quickstart':212 '/docs/reference/nextjs/clerk-middleware':423 '/docs/references/nextjs/auth':635 '/docs/references/react/use-user':853 '/docs/webhooks/sync-data':1425 '/lib/prisma':939,1115,1468 '/onboarding':113 '/page.tsx':132,146 '/premium':361 '/select-org':532,952 '/settings':261 '/sign-in':90,272,482,525,796 '/sign-up':47,97,273 '0':501,705,1263,1298 '14/15':35 '200':1327 '201':1549 '400':1179,1235 '401':1489,1529,1571 '403':1581 '4kb':1684 'access':367,427,528,639,826,930,1000,1015,1049,1651,1716,1886,1896,1903 'account':1091 'action':539 'ad':2043 'add':416,1397,1791,1882,1931 'address':1247,1262,1265,1281,1297,1300 'admin':341,344,353,997,999,1002,1012,1014,1018,1575,1583 'admin-on':1582 'adminpanel':986 'advanc':325 'algolia':2013 'algolia-search':2012 'alon':1623 'alt':701 'alway':318,822,1035,1378,1633,1657 'analyt':2022 'anti':170,368,586,809,1021,1361,1618 'anyon':1369 'api':321,323,1429,1433,1779,1786,1799,2016 'app':27,36,53,169,182,597,1442,1706,1826,1840 'app/actions/posts.ts':543 'app/api/admin/users/route.ts':1554 'app/api/projects/route.ts':1460 'app/api/webhooks/clerk/route.ts':1099 'app/create-org/page.tsx':888 'app/dashboard/page.tsx':458,931 'app/layout.tsx':114,190 'app/org-settings/page.tsx':902 'app/sign-in':128 'app/sign-up':142 'arriv':1410 'ask':2133 'async':278,333,472,510,551,595,942,1117,1474,1512,1556,1609,1704,1824 'auth':3,8,17,55,60,193,197,241,279,334,428,434,439,462,478,504,521,541,547,559,591,593,602,607,621,624,640,656,816,844,933,948,1041,1436,1445,1452,1462,1481,1521,1563,1635,1662,1691,1702,1717,1789,1795,1819,1822,1833,1838,1887,1936,2050 'auth.protect':235,288,340,350,363 'authent':12,426,1394,1447,2044,2056 'authorid':582 'await':287,339,349,362,477,492,520,558,578,590,601,606,947,960,1142,1184,1255,1289,1316,1480,1499,1520,1532,1536,1562,1588,1817,1831,1835,1837 'b2b':860 'backward':1601 'base':328,975 'basic':43 'best':222 'block':1383,1711,1879 'bodi':1181,1187,1204,1531 'body.name':1540 'boundari':2141 'built':59 'button':707 'bypass':1628,1673 'catch':1222 'caus':375,1048,1680,1725 'cdp':2025 'central':239 'chang':1087 'check':507,526,542,613,627,813,823,1007,1553,1642,1739,1790,1796,1890,1893,1907,1908 'children':123,124,127,513,514,537 'claim':444 'clarif':2135 'clariti':268 'clear':2108 'clerk':2,7,11,16,31,74,79,86,93,100,108,865,1070,1135,1392,1438,1740,1748,1759,1766,1798,1803,1811,1911,1918,1926,1970,2007,2049 'clerk-auth':1 'clerk.com':211,422,634,852,1061,1064,1424,1427,1665 'clerk.com/articles/how-to-sync-clerk-user-data-to-your-database':1426 'clerk.com/articles/multi-tenancy-in-react-applications-guide':1063 'clerk.com/docs/guides/organizations':1060 'clerk.com/docs/guides/protecting-pages':1664 'clerk.com/docs/nextjs/getting-started/quickstart':210 'clerk.com/docs/reference/nextjs/clerk-middleware':421 'clerk.com/docs/references/nextjs/auth':633 'clerk.com/docs/references/react/use-user':851 'clerk.com/docs/webhooks/sync-data':1423 'clerk/nextjs':118,136,150,163,675,720,772,892,906,921,983 'clerk/nextjs/server':252,465,549,935,1111,1464,1607 'clerkid':1258,1292,1319,1338,1360,1997 'clerkmiddlewar':199,208,219,249,277,332,452,1693 'clerkprovid':39,51,116,173,188 'client':636,643,670,715,765,768,840,978,1744,1764,1900,1923,1933 'code':67,245,456,666,883,1097,1458,1745 'collabor':1985 'come':1390 'compat':1602 'complet':30 'compon':48,50,176,391,425,432,460,637,644,766,834,841,849,992,1901,1915,1924,1930 'components/header.tsx':156,916 'components/userprofile.tsx':668 'comprehens':417 'condit':1406,1699 'config':291,406 'configur':202,455,1694 'conflict':376,1681 'console.error':1224 'const':257,269,290,475,490,516,556,566,576,604,679,684,724,728,784,788,945,958,987,1122,1140,1144,1151,1158,1182,1186,1192,1238,1244,1278,1313,1477,1497,1517,1530,1534,1559,1586,1614 'constant':1054 'content':807,1003,1019 'context':56,713 'cooki':1687 'count':486,615 'creat':572,1418 'createdat':1350 'createorgan':890 'createorgpag':896 'createpost':553 'createroutematch':221,231,250,259,271 'creation':886 'criteria':2144 'critic':1676 'css':301 'csv':313 'cuid':1337 'current':664,742 'currentus':436,445,463,493,610,628,846 'custom':2004 'cve':1629,1669 'dashboardpag':474,944 'data':485,580,631,878,929,957,1026,1030,1257,1294,1376,1538,1655,1731,1946 'databas':1074,1990 'datetim':1351,1355 'default':120,138,152,276,331,471,509,894,908,941,1336,1352 'defin':253,263,1052 'deleg':1986 'delet':1090 'describ':2112 'detect':1857 'div':969 'docx':314 'doubl':393,1726 'e':749 'e.target.value':752 'edg':1668 'email':498,1246,1260,1261,1264,1280,1295,1296,1299,1341,2030,2033,2035 'emailaddress':500,502,706 'endpoint':1373,1713 'enterpris':879 'entir':181 'enum':1058 'env.local':71 'environ':40,69,1807,1814,2124 'environment-specif':2123 'err':1223,1228 'error':564,1133,1486,1526,1568,1578,1747,1778,1802,1821,1917,1969 'etc':659 'event':1237 'eventtyp':1239,1242,1276,1311 'evt':1199,1202 'evt.data':1254,1288,1315 'evt.type':1240 'exampl':68,246,457,667,884,1098,1459 'except':296 'exclud':1864 'exist':1852 'expert':4,13,2129 'explicit':237 'export':119,137,151,164,275,289,330,470,508,550,676,721,781,893,907,922,940,984,1116,1473,1511,1555,1608 'expos':1762 'fail':1227,1233 'fake':1375 'fallback':998 'featur':867 'fetch':953 'file':226,298,373,1679,1844,1850,1856 'filter':1036,1658,1957 'first':1248,1267,1282,1302,1910 'firstnam':497,1266,1301,1344 'fix':186,203,380,397,415,599,622,821,842,1034,1051,1377,1396,1413,1632,1656 'forbidden':1579 'form':61 'formdata':554,555 'formdata.get':568 'full':447,483 'function':121,139,153,165,438,473,511,552,677,722,782,895,909,923,943,985,1118,1475,1513,1557,1610 'g':305 'get':1138,1180,1476,1558,1611 'getauth':1594,1605,1616 'gif':308 'group':234 'handl':398,1236,1404,1419 'handler':1440,1456,1638 'hardcod':1043,1797,1810 'header':166,915,924,1105,1139,1143,1177 'headerpayload':1141 'headerpayload.get':1147,1154,1161 'high':1683,1690,1696,1737 'hit':1371 'hook':638,646,648,831,836,1912,1919,1927 'html':300 'hydrat':820 'ico':312 'id':1146,1150,1167,1207,1209,1245,1259,1279,1293,1314,1320,1333,1335 'identif':2027 'imag':1252,1273,1286,1308 'imageurl':1272,1307,1348 'img':698 'implement':9,18,859 'impli':2042,2048,2054,2060,2066,2072,2078,2085,2090,2095 'import':115,133,147,157,248,461,466,546,671,716,769,773,777,889,903,917,932,936,979,1100,1104,1108,1112,1461,1465,1469,1604 'in-handl':1454 'includ':38 'index':1359 'infinit':733 'initi':1450 'input':2138 'insid':174 'instead':1416 'integr':2003 'isload':681,688,785,793,797,801,814,824,1720,1889,1894,1906,1909 'isprotectedrout':258,285,337 'ispublicrout':270 'issignedin':682,692 'issu':1050 'jpe':304 'js':302 'json.stringify':1188 'key':49,76,81,437,647,759,970,1077,1742,1750,1761,1768,1800,1804,1812,2017 'last':1250,1270,1284,1305 'lastnam':1269,1304,1346 'layout':185 'leak':1031 'let':1198 'limit':489,618,1688,2100 'link':2005 'load':653,690,804 'logic':242,1585 'loop':379 'manag':66,901,2074 'manual':388,1006,1723 'map':756 'match':282,293,2109 'matcher':292,386,405,418 'may':1877 'medium':1701,1709,1715,1722,1729 'mem':757 'mem.organization.id':760,762 'mem.organization.name':763 'membership':726,745,988,1009 'mention':2040,2046,2052,2058,2064,2070,2076,2083,2088,2093 'menu':63 'messag':1758,1785,1809,1832,1853,1874,1902,1925,1952,1976 'middlewar':10,19,195,213,244,402,408,1384,1448,1622,1625,1672,1678,1710,1776,1783,1792,1843,1855,1881 'middleware.ts':206,225,247,372,383,1849,1860 'might':1409,1650 'miss':395,404,1134,1175,1420,1816,2146 'model':1331 'move':187 'multi':857,862,1646,1938,1962,2080 'multi-ten':856,861,1645,1937,1961,2079 'multipl':371,868,1677,1842,1854 'must':179,1751,1829,1972 'name':1249,1251,1268,1271,1283,1285,1303,1306,1539 'need':1989,1999,2010,2021,2029 'new':563,1080,1132,1173,1194,1230,1322 'next':72,84,91,98,106,299,1770 'next.js':26,34 'next/headers':1107 'next/navigation':469,776 'next/server':1472 'nextrespons':1470 'nextresponse.json':1485,1509,1525,1546,1567,1577,1591 'null':1507,1544 'object':449,651,662 'older':1596 'onchang':748 'onclick':708 'one':1848 'option':266,758 'org':352,365,869,927,955,996,1011,1495,1574,1653 'org-scop':926,954 'organ':20,527,534,665,712,725,736,739,751,854,866,876,882,885,898,912,1033,1730,1945,1955,2086 'organization-scop':875 'organization.id':754 'organization.name':743 'organizationid':963,1503,1506,1542 'organizationprofil':904 'organizationswitch':918 'orgid':443,518,530,946,950,964,1028,1039,1479,1502,1504,1519,1543,1643,1660,1735,1942,1951,1959 'orgrol':519,536,1561,1573 'orgsettingspag':910 'orgswitch':723 'output':2118 'p':968 'p.id':971 'p.name':972 'page':175 'pattern':5,14,25,171,172,191,256,369,370,387,403,419,587,588,608,810,811,829,1022,1023,1042,1362,1363,1382,1402,1597,1619,1620,1640 'payload':1183,1189 'payment':2000 'per':870,881,2018 'permiss':358,364,874,2139 'person':1492 'pk':77 'png':307 'post':573,577,585,1119,1357,1358,1514 'postgr':1992 'postgres-wizard':1991 'practic':223 'pre':58 'pre-built':57 'prefix':1772 'premium':354,357,366 'prisma':937,1113,1328,1466 'prisma.post.create':579 'prisma.project.create':1537 'prisma.project.findmany':961,1500 'prisma.user.create':1256 'prisma.user.delete':1317 'prisma.user.findmany':1589 'prisma.user.update':1290 'prisma/schema.prisma':1330 'process':1325 'process.env.clerk':1125 'profil':899,1086 'project':228,959,966,1493,1496,1498,1510,1535,1547 'projects.map':967 'protect':215,216,238,254,281,329,764,806,981,991,994,1431,1432,1451,1550,1773,1784,1793,1866 'protectedcont':783 'protectedlayout':512 'provid':178,1449,1453 'public':73,85,92,99,107,264,1400,1771,1873,1884 'publish':75 'queri':1037,1940,1953 'quick':506 'race':1405,1698 'rate':488,617 'react':780 'react.reactnode':125,515 'recommend':1599 'record':1421 'redirect':378,389,394,400,467,481,524,531,951,1724,1727 'refer':209,420,632,850,1059,1422,1663 'req':280,286,335,338,1120,1515,1612,1617 'req.json':1185,1533 'req.nexturl.pathname.startswith':347,360 'request':1121,1516,1613 'requir':198,343,356,451,1001,1016,1692,2137 'resend':2032 'resend-email':2031 'respons':1174,1231,1323 'return':126,141,155,167,440,446,494,533,584,689,693,697,737,741,803,805,897,911,925,965,993,1013,1017,1172,1229,1321,1484,1508,1524,1545,1566,1576,1590 'review':2130 'role':327,345,351,535,744,746,872,974,995,1010,1044,1053,1552 'role-bas':326,973 'root':184,229 'rootlayout':122 'rout':214,217,233,255,265,283,295,322,342,355,385,396,414,1387,1401,1430,1434,1439,1637,1774,1780,1787,1862,1870,1876,1885 'router':28,37,598,789,799,1443,1707,1827,1841 'router.push':795 'run':319,411 'safeti':2140 'schema':1329 'scope':877,928,956,1025,1733,1949,1956,2111 'search':2011,2014 'secret':80,1124,1127,1130,1137,1197,1741,1749,1760,1767 'secur':2015 'segment':2024 'segment-cdp':2023 'select':740,747 'server':424,431,459,538,545,833,848,1756,1914,1929 'server-sid':1755 'session':65,661,1685 'sessionid':442 'set':204 'setact':729,750 'setup':29,32 'sever':1675,1682,1689,1695,1700,1708,1714,1721,1728,1736,1746,1777,1801,1820,1845,1867,1891,1916,1943,1968 'sharp':1667 'side':1757 'sign':45,87,94,102,110,130,144,695,710,1082,2061,2067,2098 'sign-in':44,129 'sign-on':2097 'sign-up':143 'signatur':1095,1160,1164,1171,1217,1219,1367,1966,1975,1979 'signedin':158 'signedout':159 'signin':134 'signinbutton':160 'signinpag':140 'signout':658,685,709 'signup':148 'signuppag':154 'simpl':612 'singl':224,382,1859,2096 'sk':82 'skill':2103 'skill-clerk-auth' 'slower':619 'source-sickn33' 'specif':2125 'src':699 'sso':880,2091 'state':429,641,654,657,817,828,1718,1898 'static':297 'status':1178,1234,1326,1488,1528,1548,1570,1580 'stop':2131 'string':571,1045,1334,1339,1342,1345,1347,1349 'stripe':2002 'stripe-integr':2001 'substitut':2121 'success':2143 'svg':309 'svix':1093,1103,1145,1149,1152,1156,1159,1163,1166,1168,1170,1176,1206,1208,1211,1213,1216,1218,1381,1974,1982 'svix-id':1148,1205 'svix-signatur':1162,1215 'svix-timestamp':1155,1210 'switcher':913 'sync':24,1068,1069 'tabl':1995 'task':2107 'tenanc':858,863,1963,2081 'tenant':1647,1939 'test':78,83,2127 'throw':562,1131 'timestamp':1153,1157,1169,1212,1214 'titl':567,569,581 'token':1686 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'toward':487,616 'transact':2034 'treat':2116 'tri':1201 'trigger':1987 'trpc':324 'true':734 'trust':1621 'ttf':310 'typescript':1057 'typo':1047 'ui':887,976 'unauthor':565,1487,1527,1569 'undefin':818 'uniqu':1340,1343 'updatedat':1354,1356 'upsert':1415 'url':89,96,104,112,1253,1274,1287,1309 'use':192,218,230,381,433,503,544,600,609,623,645,669,714,767,830,843,977,990,1056,1075,1092,1414,1435,1444,1593,1754,1765,1806,1813,1836,1858,1932,1935,1981,2038,2101 'useauth':655,673,686,770,787 'useeffect':778,791 'useorgan':663,717,727,980,989 'useorganizationlist':718,731 'user':23,62,448,484,491,496,499,630,650,680,871,1067,1071,1081,1085,1089,1332,1395,1490,1587,1592,1649,1897,1904,1988,1994,1998,2008,2009,2019,2020,2026,2028,2039,2045,2051,2055,2057,2063,2069,2073,2075,2082,2087,2092 'user.created':1079,1243,1408 'user.deleted':1088,1312 'user.emailaddresses':704 'user.fullname':702,703 'user.imageurl':700 'user.updated':1084,1277,1412 'user/auth':827 'userbutton':161,919 'userid':441,476,480,517,523,557,561,575,583,605,626,786,794,798,802,1478,1483,1505,1518,1523,1541,1560,1565,1615 'usermembership':730,732 'usermemberships.data':755 'userout':774,790 'userprofil':678 'usesess':660 'useus':649,672,683 'valid':1738,2126 'valu':753,761 'variabl':41,70,1808,1815 'verif':1096,1226,1232,1457,1967,1980 'verifi':1190,1365,1379,1634,1973,1984 'vulner':1674 'warn':1846,1868,1892,1944 'webhook':21,1066,1076,1078,1101,1123,1126,1129,1136,1191,1195,1196,1225,1324,1366,1386,1389,1697,1712,1861,1869,1875,1964,1971,1977 'webhookev':1109,1200,1221 'webmanifest':317 'webp':306 'welcom':495 'wh':1193 'wh.verify':1203 'without':194,1769,1775,1788,1888,1905,1941,1954,1965,1978 'wizard':1993 'woff2':311 'won':409 'work':838,1921 'wrap':52,180 'xlsx':315 'zip':316","prices":[{"id":"b42cbecf-e022-47da-9115-7a12c682c1a0","listingId":"414ce2a3-fb87-49b0-9faf-e6c9d42a0f97","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:34:27.298Z"}],"sources":[{"listingId":"414ce2a3-fb87-49b0-9faf-e6c9d42a0f97","source":"github","sourceId":"sickn33/antigravity-awesome-skills/clerk-auth","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/clerk-auth","isPrimary":false,"firstSeenAt":"2026-04-18T21:34:27.298Z","lastSeenAt":"2026-04-24T12:50:46.648Z"},{"listingId":"414ce2a3-fb87-49b0-9faf-e6c9d42a0f97","source":"skills_sh","sourceId":"sickn33/antigravity-awesome-skills/clerk-auth","sourceUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/clerk-auth","isPrimary":true,"firstSeenAt":"2026-04-23T00:40:55.580Z","lastSeenAt":"2026-04-23T00:40:55.580Z"}],"details":{"listingId":"414ce2a3-fb87-49b0-9faf-e6c9d42a0f97","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"clerk-auth","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34882,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-24T06:41:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"dac82d0317d53cbd900efe3c172ec43fc1066d7c","skill_md_path":"skills/clerk-auth/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/clerk-auth"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"clerk-auth","description":"Expert patterns for Clerk auth implementation, middleware,"},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/clerk-auth"},"updatedAt":"2026-04-24T12:50:46.648Z"}}