clerk-nextjs-patterns

Par clerk · skills

Patterns avancés Next.js - middleware, Server Actions, mise en cache avec

npx skills add https://github.com/clerk/skills --skill clerk-nextjs-patterns

Modèles Next.js

Version : Vérifiez package.json pour la version du SDK — voir la skill clerk pour la table des versions. Les différences Core 2 sont notées inline avec des callouts > **Core 2 ONLY (skip if current SDK):**.

Pour la configuration de base, voir la skill clerk-setup.

De Quoi Avez-Vous Besoin ?

Tâche Référence
Auth serveur vs client (auth() vs hooks) references/server-vs-client.md
Configurer le middleware (public-first vs protected-first) references/middleware-strategies.md
Protéger les Server Actions references/server-actions.md
Auth sur les routes API (401 vs 403) references/api-routes.md
Mettre en cache les données auth (user-scoped caching) references/caching-auth.md

Références

Référence Description
references/server-vs-client.md await auth() vs hooks
references/middleware-strategies.md Public-first vs protected-first, proxy.ts (Next.js <=15: middleware.ts)
references/server-actions.md Protéger les mutations
references/api-routes.md 401 vs 403
references/caching-auth.md User-scoped caching

Modèle Mental

Server vs Client = APIs d'authentification différentes :

  • Server : await auth() depuis @clerk/nextjs/server (async !)
  • Client : hook useAuth() depuis @clerk/nextjs (sync)

Ne les mélangez jamais. Les Server Components utilisent les imports serveur, les Client Components utilisent les hooks.

Propriétés clés de auth() :

  • isAuthenticated — booléen, remplace le pattern !!userId
  • sessionStatus'active' | 'pending', pour détecter les tâches de session incomplètes
  • userId, orgId, orgSlug, has(), protect() — inchangées

Core 2 ONLY (skip if current SDK): isAuthenticated et sessionStatus ne sont pas disponibles. Vérifiez !!userId à la place.

Modèle Minimal

// Server Component
import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  const { isAuthenticated, userId } = await auth()  // MUST await!
  if (!isAuthenticated) return <p>Not signed in</p>
  return <p>Hello {userId}</p>
}

Core 2 ONLY (skip if current SDK): isAuthenticated n'est pas disponible. Utilisez if (!userId) à la place.

Rendu Conditionnel avec <Show>

Pour le rendu conditionnel côté client basé sur l'état d'authentification :

import { Show } from '@clerk/nextjs'

<Show when="signed-in" fallback={<p>Please sign in</p>}>
  <Dashboard />
</Show>

Core 2 ONLY (skip if current SDK): Utilisez les composants <SignedIn> et <SignedOut> à la place de <Show>. Voir la skill clerk-custom-ui, core-3/show-component.md pour la table de migration complète.

Pièges Courants

Symptôme Cause Solution
undefined userId dans Server Component Missing await await auth() pas auth()
Auth ne fonctionne pas sur les routes API Matcher manquant Ajoutez '/(api|trpc)(.*)' à proxy.ts (Next.js <=15: middleware.ts)
Cache retourne les données d'un autre utilisateur userId manquant dans la clé Incluez userId dans la clé unstable_cache
Les mutations contournent l'auth Server Action non protégée Vérifiez auth() au début de l'action
Code d'erreur HTTP incorrect Confusion 401/403 401 = non connecté, 403 = pas de permission

Tokens de Session & JWTs Personnalisés

getToken() pour les APIs externes

Passez un JWT personnalisé aux services tiers (Hasura, Supabase, etc.) en utilisant les modèles JWT définis dans le dashboard Clerk.

Côté serveur (Server Component ou Route Handler) :

import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  const { getToken } = await auth()
  const token = await getToken({ template: 'hasura' })
  if (!token) return <p>Not authenticated</p>

  const res = await fetch('https://api.example.com/graphql', {
    headers: { Authorization: `Bearer ${token}` },
  })
  const data = await res.json()
  return <pre>{JSON.stringify(data)}</pre>
}

Côté client (Client Component) :

'use client'
import { useAuth } from '@clerk/nextjs'

export function DataFetcher() {
  const { getToken } = useAuth()

  async function fetchData() {
    const token = await getToken({ template: 'supabase' })
    if (!token) return

    const res = await fetch('https://api.example.com/data', {
      headers: { Authorization: `Bearer ${token}` },
    })
    return res.json()
  }

  return <button onClick={fetchData}>Fetch</button>
}

getToken() retourne null quand l'utilisateur n'est pas authentifié — vérifiez toujours avant utilisation.

useSession() pour les métadonnées de session

Accédez aux métadonnées de session dans les composants client :

'use client'
import { useSession } from '@clerk/nextjs'

export function SessionInfo() {
  const { session } = useSession()
  if (!session) return null

  return (
    <p>
      Session {session.id} — last active: {session.lastActiveAt.toISOString()}
    </p>
  )
}

Vérification manuelle de JWT (sans middleware Clerk)

Pour les serveurs API autonomes qui reçoivent des tokens de session Clerk depuis le header Authorization ou le cookie __session (same-origin).

Utilisant verifyToken de @clerk/backend (recommandé) :

import { verifyToken } from '@clerk/backend'

const token = req.headers.authorization?.replace('Bearer ', '')
if (!token) return res.status(401).json({ error: 'No token' })

try {
  const claims = await verifyToken(token, {
    jwtKey: process.env.CLERK_JWT_KEY,
  })
  // claims.sub = userId
} catch {
  return res.status(401).json({ error: 'Invalid token' })
}

Utilisant jsonwebtoken (quand vous ne pouvez pas utiliser @clerk/backend) :

import jwt from 'jsonwebtoken'

const publicKey = process.env.CLERK_PEM_PUBLIC_KEY!.replace(/\\n/g, '\n')
const token = req.headers.authorization?.replace('Bearer ', '')
if (!token) return res.status(401).json({ error: 'No token' })

try {
  const claims = jwt.verify(token, publicKey, { algorithms: ['RS256'] }) as jwt.JwtPayload
  // Vérifiez manuellement exp et nbf (jsonwebtoken fait cela automatiquement, mais vérifiez azp si nécessaire)
  // claims.sub = userId
} catch {
  return res.status(401).json({ error: 'Invalid or expired token' })
}

Sources de tokens :

  • Requêtes same-origin : cookie __session (Clerk le configure automatiquement)
  • Cross-origin / mobile / API-to-API : header Authorization: Bearer <token>

CRITIQUE : Vérifiez toujours les claims exp et nbf. verifyToken depuis @clerk/backend gère cela automatiquement ; avec jsonwebtoken brut, définissez ignoreExpiration: false (par défaut) et assurez-vous que clockTolerance est minimal.

Voir aussi

  • clerk-setup
  • clerk-orgs

Docs

Next.js SDK

Skills similaires