agentsclimarketplace

Api auth clerk

Skill agents-inc/skills/dist/plugins/api-auth-clerk/skills/api-auth-clerk

The official skills marketplace for Agents Inc, an agent composition framework that builds stacks and compiles specialized subagents for Claude Code

Install
npx -y skills add agents-inc/skills --skill api-auth-clerk

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 18 stars18 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Clerk managed authentication - ClerkProvider, middleware, pre-built components, hooks, server-side auth, organizations, webhooks

SKILL.md

16.2 KB, as published. Nobody here has run it

Clerk Authentication Patterns

Quick Guide: Clerk provides managed authentication with pre-built UI components, server-side helpers, and organization-based multi-tenancy. Use clerkMiddleware() for route protection, <Show> for conditional rendering, hooks for client state, and auth()/currentUser() for server-side auth. Clerk Core 3 (2026) replaces <SignedIn>/<SignedOut> with <Show>, renames the middleware file to proxy.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() and createRouteMatcher()
  • 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:


<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:

  1. 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).
  2. Server-first auth -- Use auth() and currentUser() in Server Components and Route Handlers. Only use client hooks (useUser, useAuth) when you need reactive client-side state.
  3. Pre-built over custom -- Use Clerk's <SignIn>, <SignUp>, <UserButton> components. Only build custom flows when the pre-built components genuinely cannot meet requirements.
  4. 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.
  5. 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 for full setup examples.

Key rules:

  • ClerkProvider goes inside <body>, not wrapping <html> -- Core 3 requires this
  • Use NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY env var, never hardcode keys
  • Middleware file is proxy.ts on Next.js 16+ or middleware.ts on Next.js <=15
  • Webhook endpoint must be in the public routes list (verified separately by verifyWebhook)
  • CLERK_WEBHOOK_SIGNING_SECRET is the env var for webhook signing (not CLERK_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 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 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.firstName, user.emailAddresses, etc.

Why good: Prevents hydration errors from accessing undefined during init, prevents TypeError from accessing null when signed out

// BAD: Accessing user without guards
const { user } = useUser();
return <p>{user.firstName}</p>; // Runtime error when isLoaded=false or isSignedIn=false

Why bad: user is undefined until loaded and null when signed out

Key hooks:

  • useUser() -- user profile data (name, email, avatar)
  • useAuth() -- session tokens (getToken()), userId, orgId, has() for authorization
  • useOrganization() -- active org data, membership, paginated members list
  • useReverification() -- re-authenticate before sensitive actions (Core 3)

In Core 3, getToken() throws ClerkOfflineError when offline instead of returning null -- always wrap in try/catch.


Pattern 4: Server-Side Authentication

Use auth() and currentUser() from @clerk/nextjs/server. See examples/server.md for complete examples.

auth() -- lightweight, no API call, reads session claims:

import { auth } from "@clerk/nextjs/server";
const { userId, orgId, isAuthenticated, redirectToSignIn } = await auth();
if (!isAuthenticated) return redirectToSignIn();

currentUser() -- full user object, makes Backend API call:

import { currentUser } from "@clerk/nextjs/server";
const user = await currentUser();
// CRITICAL: Pick safe fields before passing to client components
const safeData = { firstName: user.firstName, imageUrl: user.imageUrl };

Why critical: currentUser() returns privateMetadata that must never reach the client. Explicitly pick fields.

Defense in depth: Auth MUST be checked in every Server Action and Route Handler, not just middleware:

"use server";
const { userId } = await auth();
if (!userId) throw new Error("Unauthorized");
// userId scopes all queries/mutations to current user

Pattern 5: Authorization with Roles and Permissions

Use auth.protect() or has() for granular access control. See examples/organizations.md for RBAC patterns.

// Middleware: role-based route protection
await auth.protect((has) => has({ role: "org:admin" }));

// Server Component: permission check
const { has } = await auth();
if (!has({ permission: "org:invoices:delete" })) redirect("/dashboard");

// Client: conditional rendering by role
<Show when={{ role: "org:admin" }}><AdminPanel /></Show>

Permission format: org:<feature>:<action> (e.g., org:invoices:create, org:reports:read)

Default roles: org:admin (all permissions), org:member (read-only). Custom roles configured in Clerk Dashboard.


Pattern 6: Webhook Handling

Use Clerk webhooks (via Svix) to sync user data to your database. See examples/server.md for complete handler.

import { verifyWebhook } from "@clerk/nextjs/webhooks";

export async function POST(req: Request) {
  const evt = await verifyWebhook(req); // reads CLERK_WEBHOOK_SIGNING_SECRET env var
  // evt.type: "user.created" | "user.updated" | "user.deleted" | "organization.*" | ...
  // evt.data: UserJSON | OrganizationJSON | etc.
}

Why good: verifyWebhook validates Svix signature, always returns 200 to prevent retries, webhook route is public in middleware (verified by signature not by auth)

// BAD: No signature verification
const body = await req.json(); // Anyone can POST fake data!
await db.insert(users).values(body.data); // Security vulnerability

Why bad: No signature verification means anyone can send fake webhook events to your endpoint

Import types from @clerk/shared/types (Core 3): UserJSON, OrganizationJSON, OrganizationMembershipJSON

</patterns>

<decision_framework>

Decision Framework

Client vs Server Auth

Where do you need auth data?
|-- Server Component, Route Handler, Server Action
|   |-- Need just userId/sessionId? --> auth()
|   |-- Need full user object? --> currentUser()
|   |-- Need to protect the route? --> auth.protect()
|   +-- Need org context? --> auth() returns orgId, orgRole
|
+-- Client Component (interactive UI)
    |-- Need user profile data? --> useUser()
    |-- Need session/token data? --> useAuth()
    |-- Need org data? --> useOrganization()
    +-- Need low-level Clerk API? --> useClerk()

Route Protection Strategy

What kind of route is it?
|-- Public (landing, sign-in, sign-up, webhooks)
|   +-- Add to isPublicRoute matcher, skip auth.protect()
|
|-- Authenticated (dashboard, profile, settings)
|   +-- auth.protect() in middleware + auth() check in data layer
|
+-- Authorized (admin, org-specific, permission-gated)
    |-- Role-based? --> auth.protect({ role: "org:admin" })
    +-- Permission-based? --> auth.protect((has) => has({ permission: "org:feature:action" }))

Component Choice

What auth UI do you need?
|-- Full sign-in page --> <SignIn /> on catch-all route
|-- Full sign-up page --> <SignUp /> on catch-all route
|-- Sign-in button (modal) --> <SignInButton />
|-- User avatar + menu --> <UserButton />
|-- Full profile editor --> <UserProfile />
|-- Org switcher --> <OrganizationSwitcher />
+-- Conditional content --> <Show when="signed-in"> or <Show when={{ role: "..." }}>

</decision_framework>


<red_flags>

RED FLAGS

High Priority Issues:

  • Importing server helpers from @clerk/nextjs instead of @clerk/nextjs/server (breaks in Server Components)
  • Using deprecated <SignedIn>/<SignedOut>/<Protect> components (removed in Core 3)
  • Passing full currentUser() object to client components (leaks privateMetadata)
  • Trusting webhook payloads without verifyWebhook signature verification
  • Relying solely on middleware for route protection (middleware can be bypassed)
  • Importing types from @clerk/types instead of @clerk/shared/types (Core 3 rename)

Medium Priority Issues:

  • Not checking isLoaded before accessing hook data (causes hydration errors)
  • Using currentUser() on the client side (it is server-only)
  • Hardcoding Clerk keys instead of using environment variables
  • Using authMiddleware() (deprecated, replaced by clerkMiddleware())
  • Not making webhook endpoint public in middleware matcher
  • Using CLERK_WEBHOOK_SECRET instead of CLERK_WEBHOOK_SIGNING_SECRET

Common Mistakes:

  • Naming middleware file middleware.ts on Next.js 16+ (should be proxy.ts) or proxy.ts on Next.js <=15 (should be middleware.ts)
  • Forgetting catch-all segments [[...sign-in]] on sign-in/sign-up pages (breaks multi-step flows)
  • Using getToken() without try/catch in Core 3 (throws ClerkOfflineError when offline instead of returning null)
  • Not adding prefetch={false} to <Link> components pointing at protected routes from public pages

Gotchas & Edge Cases:

  • currentUser() counts against Backend API rate limits -- prefer useUser() hook on the client when possible
  • auth() in Server Components is deduplicated per request (safe to call multiple times)
  • <Show when={{ role: "org:admin" }}> requires an active organization in the session
  • Organization roles use the org: prefix (e.g., org:admin, org:member, org:billing)
  • Clerk Core 3 requires Node.js 20.9.0+, Next.js 15.2.3+
  • @clerk/clerk-react renamed to @clerk/react in Core 3 -- update imports after upgrade

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

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)

Failure to follow these rules will create authentication vulnerabilities or break on Clerk Core 3.

</critical_reminders>

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.