Communitygithub.com

agents-inc/skills

Autenticación gestionada por Clerk: ClerkProvider, middleware, componentes preconstruidos, hooks, autenticación del lado del servidor, organizaciones y webhooks

¿Qué es skills?

Este skill proporciona un conjunto completo de patrones y mejores prácticas para integrar Clerk, una plataforma de autenticación gestionada, en aplicaciones Next.js con TypeScript. Cubre todo el ciclo de vida de la autenticación: configuración de ClerkProvider y middleware (usando `clerkMiddleware()` y `createRouteMatcher()`), el uso de componentes de UI preconstruidos (como `<SignIn>`, `<SignUp>`, `<UserButton>` y el nuevo componente `<Show>` de Core 3 que reemplaza a `<SignedIn>`/`<SignedOut>`), hooks del lado del cliente para estado reactivo (`useUser`, `useAuth`, `useSession`, `useOrganization`), y helpers del lado del servidor (`auth()`, `currentUser()`) para Server Components, Route Handlers y Server Actions. También aborda la autorización basada en organizaciones con roles y permisos (RBAC), la protección de rutas en múltiples capas (middleware y capa de datos) y el manejo seguro de webhooks mediante la verificación de firmas con `verifyWebhook`. El skill enfatiza principios clave como defensa en profundidad, autenticación primero en el servidor, y el uso de componentes preconstruidos sobre flujos personalizados, detallando además las migraciones necesarias para Clerk Core 3 y las prácticas de seguridad críticas como no filtrar `privateMetadata` al cliente ni confiar en payloads de webhook sin verificar.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/agents-inc/skills/tree/HEAD/src/skills/api-auth-clerk

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de Autenticación con Clerk

Guía rápida: Clerk proporciona autenticación gestionada con componentes de UI preconstruidos, ayudantes del lado del servidor y multi-tenant basado en organizaciones. Usa clerkMiddleware() para proteger rutas, <Show> para renderizado condicional, hooks para el estado del cliente, y auth()/currentUser() para autenticación del lado del servidor. Clerk Core 3 (2026) reemplaza <SignedIn>/<SignedOut> con <Show>, renombra el archivo de middleware a proxy.ts (Next.js 16+) y consolida los paquetes.


<critical_requirements>

CRÍTICO: Antes de Usar Este Skill

Todo el código debe seguir las convenciones del proyecto en CLAUDE.md (kebab-case, exportaciones nombradas, orden de importaciones, import type, constantes nombradas)

(DEBES usar @clerk/nextjs/server para TODAS las importaciones del lado del servidor -- NUNCA importes ayudantes del servidor desde @clerk/nextjs)

(DEBES verificar los webhooks usando el helper verifyWebhook de Clerk -- NUNCA confíes en payloads de webhook no verificados)

(DEBES usar el componente <Show> en lugar de los obsoletos <SignedIn>/<SignedOut>/<Protect> -- estos se eliminan en Core 3)

(NO DEBES pasar el objeto completo de currentUser() al cliente -- contiene privateMetadata que debe permanecer en el servidor)

(DEBES proteger las rutas TANTO en el middleware COMO en la capa de acceso a datos -- el middleware solo es insuficiente)

</critical_requirements>


Auto-detección: 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"

Cuándo usar:

  • Agregar autenticación y gestión de usuarios a una aplicación
  • Construir aplicaciones B2B multi-tenant con control de acceso basado en organizaciones
  • Usar componentes de UI preconstruidos para inicio de sesión/registro con personalización de temas
  • Proteger rutas con middleware y verificaciones de autorización del lado del servidor
  • Sincronizar datos de usuario de Clerk con tu base de datos mediante webhooks

Patrones clave cubiertos:

  • Configuración de ClerkProvider, variables de entorno, configuración de middleware
  • Componentes de UI preconstruidos (<SignIn>, <SignUp>, <UserButton>, <Show>)
  • Hooks del lado del cliente (useUser, useAuth, useSession, useOrganization)
  • Autenticación del lado del servidor (auth(), currentUser()) en Server Components, Route Handlers, Server Actions
  • Protección de rutas con middleware usando clerkMiddleware() y createRouteMatcher()
  • Multi-tenant basado en organizaciones con roles y permisos
  • Manejo de webhooks con verificación de firma Svix

Cuándo NO usar:

  • Requisito de autenticación autoalojada (necesitas control total sobre el almacenamiento de datos de autenticación)
  • No se puede usar un servicio de autenticación de terceros (restricciones regulatorias/de cumplimiento)
  • Autenticación simple con clave API (el middleware personalizado es suficiente)
  • Restricciones presupuestarias impiden usar un servicio gestionado

Recursos detallados:


Filosofía

Clerk es una plataforma de autenticación gestionada que maneja todo el ciclo de vida de autenticación: registro, inicio de sesión, gestión de sesiones, perfiles de usuario, organizaciones y MFA. En lugar de construir la autenticación desde cero, integras el SDK de Clerk y sus componentes preconstruidos.

Principios fundamentales:

  1. Defensa en profundidad -- Protege las rutas en la capa de middleware Y verifica la autenticación en cada punto de acceso a datos. El middleware solo es insuficiente (CVE-2025-29927 demostró vulnerabilidades de omisión del middleware).
  2. Autenticación primero en el servidor -- Usa auth() y currentUser() en Server Components y Route Handlers. Usa hooks del cliente (useUser, useAuth) solo cuando necesites estado reactivo en el cliente.
  3. Preconstruido sobre personalizado -- Usa los componentes <SignIn>, <SignUp>, <UserButton> de Clerk. Solo construye flujos personalizados cuando los componentes preconstruidos realmente no puedan cumplir con los requisitos.
  4. Organizaciones para multi-tenant -- Usa las Organizaciones de Clerk con roles y permisos para aplicaciones B2B. No construyas sistemas de tenant personalizados sobre el modelo de usuario de Clerk.
  5. Sincronización impulsada por webhooks -- Sincroniza los datos de Clerk con tu base de datos mediante webhooks, no mediante sondeo. Siempre verifica las firmas de los webhooks con verifyWebhook.

Cuándo usar Clerk:

  • Necesitas autenticación rápidamente con un mínimo de código personalizado
  • Quieres componentes de UI preconstruidos para inicio de sesión/registro/gestión de usuarios
  • Necesitas multi-tenant basado en organizaciones con RBAC
  • Quieres MFA, SSO (SAML/OIDC) e inicio de sesión social gestionados

Cuándo NO usar Clerk:

  • Necesitas control total sobre el almacenamiento de datos de autenticación (requisito autoalojado)
  • No puedes usar un servicio de autenticación de terceros (restricciones regulatorias/de cumplimiento)
  • Tu aplicación solo necesita autenticación simple con clave API
  • Restricciones presupuestarias impiden usar un servicio gestionado

Patrones Esenciales

Patrón 1: Configuración de ClerkProvider y Middleware

Cada aplicación Clerk necesita <ClerkProvider> envolviendo la aplicación y clerkMiddleware() protegiendo las rutas. Consulta examples/core.md para ejemplos completos de configuración.

Reglas clave:

  • ClerkProvider va dentro de <body>, no envolviendo <html> -- Core 3 lo requiere
  • Usa la variable de entorno NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, nunca codifiques las claves
  • El archivo de middleware es proxy.ts en Next.js 16+ o middleware.ts en Next.js <=15
  • El endpoint del webhook debe estar en la lista de rutas públicas (verificado por separado por verifyWebhook)
  • CLERK_WEBHOOK_SIGNING_SECRET es la variable de entorno para la firma del webhook (no CLERK_WEBHOOK_SECRET)
// proxy.ts (Next.js 16+) o 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();
  }
});

Por qué es bueno: Las rutas públicas se incluyen explícitamente en la lista blanca, todo lo demás requiere autenticación, el endpoint del webhook es público (verificado por separado)

// MALO: clerkMiddleware() sin callback
export default clerkMiddleware(); // ¡TODAS las rutas son PÚBLICAS por defecto!

Por qué es malo: clerkMiddleware() sin callback adjunta datos de autenticación pero no protege ninguna ruta


Patrón 2: Componentes de UI Preconstruidos y <Show>

Usa <Show> para el renderizado condicional (reemplazo de Core 3 para <SignedIn>/<SignedOut>/<Protect>). Consulta examples/components.md para ejemplos completos.

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

Por qué es bueno: <Show> es la API de Core 3, soporta condiciones de cadena/objeto/función de callback, prop fallback para no autorizado

// MALO: Obsoleto -- eliminado en Core 3
<SignedIn>...</SignedIn>
<SignedOut>...</SignedOut>
<Protect role="admin">...</Protect>

Por qué es malo: <SignedIn>, <SignedOut>, <Protect> se eliminan en Core 3, usa <Show> con la prop when

Las páginas de inicio de sesión/registro requieren segmentos de ruta comodín [[...sign-in]] para flujos de varios pasos (MFA, callbacks OAuth).


Patrón 3: Hooks del Lado del Cliente

Usa hooks en Client Components para el estado de autenticación reactivo. Siempre verifica isLoaded antes de acceder a los datos. Consulta examples/hooks.md para ejemplos completos.

"use client";
const { isLoaded, isSignedIn, user } = useUser();
if (!isLoaded) return <div>Loading...</div>;
if (!isSignedIn) return <div>Please sign in</div>;
// Ahora es seguro acceder a user.firstName, user.emailAddresses, etc.

Por qué es bueno: Previene errores de hidratación al acceder a undefined durante la inicialización, previene TypeError al acceder a null cuando no has iniciado sesión

// MALO: Acceder a user sin protecciones
const { user } = useUser();
return <p>{user.firstName}</p>; // Error en tiempo de ejecución cuando isLoaded=false o isSignedIn=false

Por qué es malo: user es undefined hasta que se carga y null cuando no has iniciado sesión

Hooks clave:

  • useUser() -- datos del perfil del usuario (nombre, email, avatar)
  • useAuth() -- tokens de sesión (getToken()), userId, orgId, has() para autorización
  • useOrganization() -- datos de la organización activa, membresía, lista paginada de miembros
  • useReverification() -- re-autenticación antes de acciones sensibles (Core 3)

En Core 3, getToken() lanza ClerkOfflineError cuando está desconectado en lugar de devolver null -- siempre envuélvelo en try/catch.


Patrón 4: Autenticación del Lado del Servidor

Usa auth() y currentUser() desde @clerk/nextjs/server. Consulta examples/server.md para ejemplos completos.

auth() -- ligero, sin llamada API, lee las reclamaciones de la sesión:

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

currentUser() -- objeto de usuario completo, realiza una llamada a la API de Backend:

import { currentUser } from "@clerk/nextjs/server";
const user = await currentUser();
// CRÍTICO: Selecciona campos seguros antes de pasarlos a los componentes del cliente
const safeData = { firstName: user.firstName, imageUrl: user.imageUrl };

Por qué es crítico: currentUser() devuelve privateMetadata que nunca debe llegar al cliente. Selecciona los campos explícitamente.

Defensa en profundidad: La autenticación DEBE verificarse en cada Server Action y Route Handler, no solo en el middleware:

"use server";
const { userId } = await auth();
if (!userId) throw new Error("Unauthorized");
// userId limita todas las consultas/mutaciones al usuario actual

Patrón 5: Autorización con Roles y Permisos

Usa auth.protect() o has() para control de acceso granular. Consulta examples/organizations.md para patrones RBAC.

// Middleware: protección de rutas basada en roles
await auth.protect((has) => has({ role: "org:admin" }));

// Server Component: verificación de permisos
const { has } = await auth();
if (!has({ permission: "org:invoices:delete" })) redirect("/dashboard");

// Cliente: renderizado condicional por rol
<Show when={{ role: "org:admin" }}><AdminPanel /></Show>

Formato de permiso: org:<feature>:<action> (ej., org:invoices:create, org:reports:read)

Roles predeterminados: org:admin (todos los permisos), org:member (solo lectura). Roles personalizados configurados en el Panel de Clerk.


Patrón 6: Manejo de Webhooks

Usa los webhooks de Clerk (a través de Svix) para sincronizar los datos de usuario con tu base de datos. Consulta examples/server.md para el manejador completo.

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

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

Por qué es bueno: verifyWebhook valida la firma Svix, siempre devuelve 200 para evitar reintentos, la ruta del webhook es pública en el middleware (verificada por la firma, no por la autenticación)

// MALO: Sin verificación de firma
const body = await req.json(); // ¡Cualquiera puede enviar datos falsos POST!
await db.insert(users).values(body.data); // Vulnerabilidad de seguridad

Por qué es malo: Sin verificación de firma, cualquiera puede enviar eventos de webhook falsos a tu endpoint

Importa tipos desde @clerk/shared/types (Core 3): UserJSON, OrganizationJSON, OrganizationMembershipJSON


<decision_framework>

Marco de Decisión

Autenticación Cliente vs Servidor

¿Dónde necesitas los datos de autenticación?
|-- Server Component, Route Handler, Server Action
|   |-- ¿Solo necesitas userId/sessionId? --> auth()
|   |-- ¿Necesitas el objeto de usuario completo? --> currentUser()
|   |-- ¿Necesitas proteger la ruta? --> auth.protect()
|   +-- ¿Necesitas contexto de org? --> auth() devuelve orgId, orgRole
|
+-- Client Component (interfaz de usuario interactiva)
    |-- ¿Necesitas datos del perfil del usuario? --> useUser()
    |-- ¿Necesitas datos de sesión/token? --> useAuth()
    |-- ¿Necesitas datos de la org? --> useOrganization()
    +-- ¿Necesitas la API de Clerk de bajo nivel? --> useClerk()

Estrategia de Protección de Rutas

¿Qué tipo de ruta es?
|-- Pública (landing, inicio de sesión, registro, webhooks)
|   +-- Añadir al matcher de isPublicRoute, omitir auth.protect()
|
|-- Autenticada (dashboard, perfil, configuración)
|   +-- auth.protect() en middleware + verificación auth() en la capa de datos
|
+-- Autorizada (admin, específica de org, con control de permisos)
    |-- ¿Basada en roles? --> auth.protect({ role: "org:admin" })
    +-- ¿Basada en permisos? --> auth.protect((has) => has({ permission: "org:feature:action" }))

Elección del Componente

¿Qué UI de autenticación necesitas?
|-- Página de inicio de sesión completa --> <SignIn /> en ruta comodín
|-- Página de registro completa --> <SignUp /> en ruta comodín
|-- Botón de inicio de sesión (modal) --> <SignInButton />
|-- Avatar de usuario + menú --> <UserButton />
|-- Editor de perfil completo --> <UserProfile />
|-- Selector de org --> <OrganizationSwitcher />
+-- Contenido condicional --> <Show when="signed-in"> o <Show when={{ role: "..." }}>

</decision_framework>


<red_flags>

BANDERAS ROJAS

Problemas de Alta Prioridad:

  • Importar ayudantes del servidor desde @clerk/nextjs en lugar de @clerk/nextjs/server (se rompe en Server Components)
  • Usar componentes obsoletos <SignedIn>/<SignedOut>/<Protect> (eliminados en Core 3)
  • Pasar el objeto completo de currentUser() a los componentes del cliente (filtra privateMetadata)
  • Confiar en payloads de webhook sin verificación de firma verifyWebhook
  • Depender únicamente del middleware para la protección de rutas (el middleware puede ser omitido)
  • Importar tipos desde @clerk/types en lugar de @clerk/shared/types (cambio de ruta en Core 3)
  • Usar variables de entorno incorrectas (ej., CLERK_WEBHOOK_SECRET en lugar de CLERK_WEBHOOK_SIGNING_SECRET)
  • No usar claves de entorno y codificarlas directamente en el código (NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY)

Problemas de Mediana Prioridad:

  • No verificar isLoaded antes de acceder a datos en hooks del cliente (causa errores de hidratación)
  • No envolver getToken() en try/catch ignorando ClerkOfflineError (Core 3)
  • Usar segmentos de ruta estáticos en lugar de comodín [[...sign-in]] para páginas de inicio de sesión

Problemas de Baja Prioridad:

  • Ubicación incorrecta de ClerkProvider (Core 3 requiere que esté dentro de <body>, no envolviendo <html>)
  • No desestructurar props de ClerkProvider antes de pasarlas (ej., pasar appearance para componentes internos)

</red_flags>


<tools_and_commands>

Comandos y Herramientas

CLI de Clerk

# Instalar Clerk en un proyecto existente
npx clerk@latest sync

# Iniciar sesión en Clerk desde el terminal
npx clerk@latest sign-in

# Listar todos los comandos disponibles
npx clerk@latest --help

Variables de Entorno

Crea un archivo .env.local (nunca .env o .env.production para evitar commits accidentales):

# OBLIGATORIO: Clave publicable del Dashboard de Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_Y2xlcmsuZXhhbXBsZS5jb20=

# OBLIGATORIO: Clave secreta del Dashboard de Clerk
CLERK_SECRET_KEY=sk_live_ZXhhbXBsZS5jb20=

# OPCIONAL: Secreto de firma para webhooks (solo si usas webhooks)
CLERK_WEBHOOK_SIGNING_SECRET=whsec_ZXhhbXBsZS5jb20=

Comandos de Referencia Rápida

ComandoDescripción
npx clerk@latest syncSincronizar la configuración local con Clerk Dashboard
npx clerk@latest sign-inIniciar sesión en Clerk CLI
npx clerk@latest --helpMostrar todos los comandos de CLI
npm install @clerk/nextjsInstalar el SDK de Clerk para Next.js (Core 2)
npm install @clerk/nextjs@core3Instalar Clerk Core 3 (Next.js 16+)

Dependencias de Paquete

{
  "dependencies": {
    "@clerk/nextjs": "^5.0.0"
  }
}

Para Core 3 (Next.js 16+):

{
  "dependencies": {
    "@clerk/nextjs": "^6.0.0-core.0"
  }
}

</tools_and_commands>


<quality_assurance>

Garantía de Calidad

Lista de Verificación de Integración

  • ClerkProvider envuelve la aplicación dentro de <body> (Core 3 no permite envolver <html>)
  • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY y CLERK_SECRET_KEY establecidas en .env.local
  • clerkMiddleware() configurado con createRouteMatcher() para rutas públicas
  • Las rutas de la API de webhook son públicas en el middleware (verificadas por separado por verifyWebhook)
  • auth.protect() o verificación auth() en cada Server Action y Route Handler
  • currentUser() nunca se pasa directamente al cliente (seleccionar campos seguros)
  • Uso de <Show> con la prop when en lugar de <SignedIn>/<SignedOut>/<Protect>
  • Los hooks del lado del cliente verifican isLoaded antes de acceder a datos
  • Las organizaciones están configuradas con roles y permisos (si se usan)
  • Los manejadores de webhook usan verifyWebhook para verificar firmas
  • Todos los imports del servidor provienen de @clerk/nextjs/server, nunca de @clerk/nextjs
  • Los tipos importados de @clerk/shared/types (Core 3) o @clerk/types (Core 2)
  • getToken() envuelto en try/catch para manejar ClerkOfflineError (Core 3)

Escenarios de Prueba

  1. Prueba básica de autenticación: Acceder a una ruta protegida sin sesión → redirigir a inicio de sesión
  2. Prueba de cierre de sesión: Cerrar sesión → no poder acceder a rutas protegidas
  3. Prueba de semilla de webhook: Enviar un webhook de prueba desde el Dashboard de Clerk → los datos aparecen en la base de datos
  4. Prueba de organización: Cambiar de organización → el contenido cambia para reflejar la organización activa
  5. Prueba de permiso: Usuario sin permiso intenta acceder a ruta restringida → redirigir/bloquear
  6. Prueba de rol: Admin vs vistas de miembro → renderizado condicional funciona
  7. Prueba de estado de carga: Esperar a que ClerkProvider cargue → no hay parpadeo de contenido no autenticado
  8. Prueba de falsificación de webhook: Enviar payload POST sin firma → el manejador rechaza (código de estado 401)

Problemas Conocidos

  • Next.js 16 cambia el nombre del archivo de middleware: Usar proxy.ts en lugar de middleware.ts (Core 3)
  • getToken() puede lanzar ClerkOfflineError: En Core 3, getToken lanza cuando está desconectado en lugar de devolver null -- siempre usar try/catch
  • La protección de middleware puede ser omitida: CVE-2025-29927 demostró que el middleware de Next.js puede ser eludido -- siempre verificar la autenticación en el backend
  • ClerkProvider no puede envolver <html>: Core 3 requiere que ClerkProvider esté dentro de <body>
  • Los tipos de webhook cambian en Core 3: Importar desde @clerk/shared/types en lugar de @clerk/types

</quality_assurance>

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Skills relacionados