Motifs Next.js
Version : Vérifiez
package.jsonpour la version du SDK — voir la skillclerkpour le tableau des versions. Les différences Core 2 sont notées en ligne avec des callouts> **Core 2 ONLY (skip if current SDK):**.
Pour la configuration de base, voir la skill clerk-setup.
Qu'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 des routes API (401 vs 403) | references/api-routes.md |
| Cacher les données d'auth (caching user-scoped) | 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 |
Caching user-scoped |
Modèle Mental
Server vs Client = APIs d'auth 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 depuis auth() :
isAuthenticated— booléen, remplace le pattern!!userIdsessionStatus—'active'|'pending', pour détecter les tâches de session incomplètesuserId,orgId,orgSlug,has(),protect()— inchangés
Core 2 ONLY (skip if current SDK):
isAuthenticatedetsessionStatusne sont pas disponibles. Vérifiez!!userIdà la place.
Motif 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):
isAuthenticatedn'est pas disponible. Utilisezif (!userId)à la place.
Rendu Conditionnel avec <Show>
Pour le rendu conditionnel côté client basé sur l'état d'auth. <Show> couvre à la fois les vérifications d'authentification et d'autorisation (feature, plan, role, permission) en un seul composant.
Vérification d'authentification :
import { Show } from '@clerk/nextjs'
<Show when="signed-in" fallback={<p>Please sign in</p>}>
<Dashboard />
</Show>
Vérifications d'autorisation (B2B) :
// Feature-based (preferred — features can move between plans without redeploy)
<Show when={{ feature: 'analytics' }} fallback={<UpgradePrompt />}>
<AnalyticsDashboard />
</Show>
// Permission-based (preferred over role-based for granular access)
<Show when={{ permission: 'org:invoices:create' }}>
<NewInvoiceButton />
</Show>
// Plan-based (tier-level gating)
<Show when={{ plan: 'pro' }}>
<ProFeatures />
</Show>
// Role-based (use sparingly — prefer permission)
<Show when={{ role: 'org:admin' }}>
<AdminPanel />
</Show>
Callback pour logique complexe :
<Show when={(has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })}>
<BillingActions />
</Show>
Core 2 ONLY (skip if current SDK):
<Show>n'existe pas. Pour l'authentification, utilisez<SignedIn>et<SignedOut>. Pour l'autorisation (role / permission), utilisez<Protect>avec les mêmes noms de props (role,permission,condition). Les variantes feature- et plan-based nécessitent Core 3. Voir la skillclerk-custom-ui,core-3/show-component.mdpour le tableau de migration complet.
Pièges Courants
| Symptôme | Cause | Solution |
|---|---|---|
undefined userId dans Server Component |
await manquant |
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 du mauvais 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 signé, 403 = pas de permission |
Session Tokens & Custom JWTs
getToken() pour les APIs externes
Passez un JWT personnalisé aux services tiers (Hasura, Supabase, etc.) en utilisant les templates 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 null avant utilisation.
useSession() pour les données de session
Accédez aux métadonnées de session dans les client components :
'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 JWT manuelle (sans middleware Clerk)
Pour les serveurs API autonomes qui reçoivent des session tokens Clerk depuis l'en-tête Authorization ou le cookie __session (same-origin).
En 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' })
}
En 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
// Manually check exp and nbf (jsonwebtoken does this automatically, but verify azp if needed)
// claims.sub = userId
} catch {
return res.status(401).json({ error: 'Invalid or expired token' })
}
Sources de token :
- Requêtes same-origin : cookie
__session(Clerk le définit automatiquement) - Cross-origin / mobile / API-to-API : en-tête
Authorization: Bearer <token>
CRITIQUE : Vérifiez toujours les claims
expetnbf.verifyTokendepuis@clerk/backendgère cela automatiquement ; avecjsonwebtokenbrut, définissezignoreExpiration: false(défaut) et assurez-vous queclockToleranceest minimal.
Voir Aussi
clerk-setup- Installation initiale de Clerkclerk-orgs- Motifs B2B (org active, gating role/permission)clerk-billing- Droits plan et feature avechas()clerk-webhooks- Synchroniser les événements utilisateur/org vers votre base de donnéesclerk-custom-ui- Thématisation et personnalisation pour les composants intégrés