NextAuth.js : tutoriel d'introduction — Credentials, sessions JWT vs base de données

Ouvrir la documentation NextAuth.js, c’est se retrouver face à une masse d’options : Provider, Session, Adapter, JWT, Callbacks… Chaque terme est familier, mais ensemble le tableau reste flou. La doc dit « JWT par défaut », puis « avec une base on bascule en Session » — laquelle choisir ?
J’ai failli abandonner pour Clerk. Clerk est rapide, mais au-delà de 10 000 utilisateurs actifs mensuels c’est payant, et beaucoup de personnalisations sont limitées. NextAuth.js demande plus d’effort au départ, mais reste gratuit et entièrement sous votre contrôle.
Cet article ne liste pas toutes les options (ce serait épuisant). Il se concentre sur le scénario Credentials — identifiant/mot de passe, gestion de session, intégration base. Une fois ces briques comprises, NextAuth.js devient beaucoup plus abordable.
Comprendre les concepts clés de NextAuth.js
Que fait vraiment NextAuth.js ?
En une phrase : c’est un middleware d’authentification qui gère qui est connecté et comment l’état de connexion est stocké. Peu importe votre base ou votre UI — NextAuth.js vérifie l’identité et persiste la session.
Comparaison avec Clerk et Supabase Auth :
- Clerk : belle UI de connexion, tableau de bord utilisateurs, prêt en 30 minutes — payant au-delà de 10 000 MAU
- Supabase Auth : si vous utilisez Supabase, l’auth est quasi incluse et très bien intégrée
- NextAuth.js : gratuit et open source — UI de connexion, inscription et logique base à construire vous-même
En 2025, NextAuth.js reste très utilisé, mais les solutions « clé en main » comme Clerk gagnent du terrain. Compréhensible — peu envie de passer des jours sur l’auth plutôt que sur le produit. Pour un projet perso ou un contrôle total, NextAuth.js vaut toujours le coup.
Trois notions indispensables
1. Provider : comment l’utilisateur se connecte ?
C’est la méthode de login. NextAuth.js en supporte plus de 50 ; les plus courantes :
- OAuth : Google, GitHub, Facebook — un clic, pas de gestion de mot de passe côté vous
- Credentials : identifiant + mot de passe — classique, et le cœur de cet article
Attention : Credentials est le plus flexible mais demande le plus de code maison. Officiellement ce n’est même pas recommandé — hash des mots de passe, anti brute-force, sessions : tout repose sur vous.
2. Session : comment l’app « se souvient » ?
Après une connexion, on ne retape pas le mot de passe à chaque requête. Deux mécanismes :
- JWT Session : infos chiffrées dans un cookie, rien côté serveur
- Database Session : cookie = ID, données en base
Le choix entre les deux est ce qui embrouille le plus les débutants — détail dans la section suivante.
3. Adapter : où sont les données utilisateur ?
Pour stocker email, date d’inscription, etc., il faut un Adapter (Prisma, MongoDB, MySQL…).
Point clé : Credentials ne crée pas automatiquement les comptes en base. Vous gérez les comptes ; NextAuth.js ne fait que valider à la connexion.
JWT vs Session : que choisir ?
C’est la question centrale. Après de nombreux articles, la différence m’est devenue claire.
JWT Session : mode passeport
Photo, nom, validité sur le document ; à la frontière, le passeport suffit. Après login, le serveur émet un token chiffré (userId, email…) stocké dans un cookie.
Avantages :
- Rapide — pas de requête base
- Économique — pas de table session, idéal serverless
- Scalable — pas de table session qui explose
Inconvénients :
- Pas de déconnexion forcée tant que le token est valide (blacklist = retour à la base)
- Pas de limite de devices simultanés
- Contenu du token figé jusqu’à expiration — rôle modifié en base ? l’ancien rôle reste dans le token
Database Session : mode carte d’hôtel
La carte ne porte que le numéro de chambre ; le détail est dans le système hôtelier. Cookie = session ID, utilisateur en base.
Avantages :
- Révocation immédiate — « déconnecter tous les appareils » = supprimer les lignes session
- Limite de devices possible
- Mise à jour live des infos (rôle, etc.)
Inconvénients :
- Requête base à chaque appel
- Maintenance de la table session
- Charge base si fort trafic
Arbre de décision
Besoin de forcer une reconnexion ? (mot de passe changé, compte gelé)
├─ Oui → Database Session
└─ Non → suite
Voulez-vous éviter la base ou déployer en serverless ?
├─ Oui → JWT
└─ Non → suite
Projet perso / MVP, mise en ligne rapide ?
├─ Oui → JWT (simple)
└─ Non → Database Session (entreprise, plus sûr)
Mon premier projet était en JWT ; avec un back-office et le besoin d’« expulser » un utilisateur, migration vers Database Session — coûteuse. Mieux vaut trancher tôt.
Cas particulier : Credentials + Database Session
La doc officielle indique que ce combo n’est pas supporté. OAuth (Google, GitHub) fonctionne ; pour Credentials, NextAuth.js n’attend pas de création automatique de session.
Des contournements existent (callback signIn manuel), voir cette discussion. En débutant : JWT ou OAuth — évitez la complexité inutile.
Configuration complète du Credentials Provider
Assez de théorie — passons au code. Trois niveaux : minimal, options détaillées, exemple complet.
Base : version minimale fonctionnelle
Dépendances :
npm install next-auth
Créer le fichier. App Router (Next.js 13+) : app/api/auth/[...nextauth]/route.ts ; Pages Router : pages/api/auth/[...nextauth].js. Exemple App Router.
app/api/auth/[…nextauth]/route.ts :
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
const handler = NextAuth({
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: "E-mail", type: "email" },
password: { label: "Mot de passe", type: "password" }
},
async authorize(credentials) {
// Utilisateur de test en dur
if (credentials?.email === "[email protected]" &&
credentials?.password === "123456") {
return {
id: "1",
name: "Utilisateur test",
email: "[email protected]"
}
}
return null // Échec de connexion
}
})
],
session: {
strategy: "jwt"
},
pages: {
signIn: '/login'
}
})
export { handler as GET, handler as POST }
Variables .env.local :
NEXTAUTH_SECRET=your-super-secret-key-change-this
NEXTAUTH_URL=http://localhost:3000
Points clés :
NEXTAUTH_SECRET: chiffre les tokens — obligatoire en prod. Génération :openssl rand -base64 32authorize: cœur de la validation — objet utilisateur = succès,null= échec
Ça tourne, mais l’utilisateur est en dur — ensuite, branchement base.
Options de configuration détaillées
1. session.strategy : jwt ou database ?
Par défaut "jwt". Avec Adapter → "database". Credentials + JWT : définir explicitement strategy: "jwt" pour éviter les erreurs.
2. callbacks : champs personnalisés dans la session
Par défaut, useSession ne renvoie que name, email, image. Pour userId ou role, utilisez les callbacks :
callbacks: {
async jwt({ token, user }) {
if (user) {
token.userId = user.id
}
return token
},
async session({ session, token }) {
session.user.userId = token.userId
return session
}
}
3. pages : page de connexion personnalisée
La page par défaut /api/auth/signin est fonctionnelle mais peu esthétique. UI maison : pages: { signIn: '/login' }.
Sur la page de login :
import { signIn } from "next-auth/react"
const handleSubmit = async (e) => {
e.preventDefault()
const result = await signIn('credentials', {
redirect: false,
email,
password
})
if (result?.error) {
// Échec
} else {
// Succès, redirection
}
}
Exemple complet : inscription + connexion + session
Avec Prisma + PostgreSQL.
1. Table utilisateur
prisma/schema.prisma :
model User {
id String @id @default(cuid())
email String @unique
password String
name String?
createdAt DateTime @default(now())
}
Puis npx prisma migrate dev.
2. API d’inscription
app/api/register/route.ts :
import { NextResponse } from "next/server"
import bcrypt from "bcryptjs"
import { prisma } from "@/lib/prisma"
export async function POST(req: Request) {
try {
const { email, password, name } = await req.json()
const existingUser = await prisma.user.findUnique({
where: { email }
})
if (existingUser) {
return NextResponse.json(
{ error: "E-mail déjà enregistré" },
{ status: 400 }
)
}
const hashedPassword = await bcrypt.hash(password, 10)
const user = await prisma.user.create({
data: {
email,
password: hashedPassword,
name
}
})
return NextResponse.json({
user: {
id: user.id,
email: user.email,
name: user.name
}
})
} catch (error) {
return NextResponse.json(
{ error: "Échec de l'inscription" },
{ status: 500 }
)
}
}
Important : hasher les mots de passe — bcrypt ou argon2, jamais en clair.
3. NextAuth avec base
app/api/auth/[...nextauth]/route.ts :
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import bcrypt from "bcryptjs"
import { prisma } from "@/lib/prisma"
const handler = NextAuth({
providers: [
CredentialsProvider({
credentials: {
email: { label: "E-mail", type: "email" },
password: { label: "Mot de passe", type: "password" }
},
async authorize(credentials) {
if (!credentials?.email || !credentials?.password) {
return null
}
const user = await prisma.user.findUnique({
where: { email: credentials.email }
})
if (!user) {
return null
}
const isValid = await bcrypt.compare(
credentials.password,
user.password
)
if (!isValid) {
return null
}
return {
id: user.id,
email: user.email,
name: user.name
}
}
})
],
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.userId = user.id
}
return token
},
async session({ session, token }) {
session.user.userId = token.userId as string
return session
}
},
pages: {
signIn: '/login'
}
})
export { handler as GET, handler as POST }
4. Utiliser la session
Server Component :
import { getServerSession } from "next-auth"
export default async function ProfilePage() {
const session = await getServerSession()
if (!session) {
redirect('/login')
}
return <div>Bienvenue, {session.user.name}</div>
}
Client Component :
'use client'
import { useSession } from "next-auth/react"
export default function Dashboard() {
const { data: session, status } = useSession()
if (status === "loading") {
return <div>Chargement…</div>
}
if (!session) {
return <div>Veuillez vous connecter</div>
}
return <div>Votre ID : {session.user.userId}</div>
}
Rappel : serveur → getServerSession() ; client → useSession() avec 'use client' et <SessionProvider> dans le layout.
Stratégies de session et problèmes fréquents
Bien utiliser la session JWT
1. Infos supplémentaires (userId, role)
Le callback jwt remplit le token ; session expose à l’app.
Exemple avec rôle :
callbacks: {
async jwt({ token, user }) {
if (user) {
token.userId = user.id
token.role = user.role
}
return token
},
async session({ session, token }) {
session.user.userId = token.userId as string
session.user.role = token.role as string
return session
}
}
2. Expiration du token
Par défaut 30 jours :
session: {
strategy: "jwt",
maxAge: 7 * 24 * 60 * 60
}
Le token survit à la fermeture du navigateur jusqu’à déconnexion manuelle. « Déconnexion à la fermeture du navigateur » = logique client, pas JWT seul.
3. Limite JWT : pas de révocation instantanée
Compte compromis ? Tant que le token est valide, l’accès continue.
Palliatifs : durée courte, blacklist (retour base), ou Database Session.
Database Session (et Credentials)
Avec OAuth, c’est simple :
npm install @next-auth/prisma-adapter
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { prisma } from "@/lib/prisma"
const handler = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
})
]
})
Tables User, Session, Account créées automatiquement ; strategy devient database.
Credentials + database session : non supporté officiellement. Workarounds via signIn — risqué pour débutants. Voir :
Sinon Clerk ou Supabase Auth.
Cinq pièges les plus courants
1. NEXTAUTH_SECRET manquant en production
En local, optionnel (avec avertissement) ; sur Vercel/Railway sans variable → 500. openssl rand -base64 32, puis variable d’environnement.
2. Credentials + database session
Adapter + Credentials → erreur. Soit session: { strategy: "jwt" }, soit logique session manuelle.
3. useSession dans un Server Component
App Router = Server Components par défaut. useSession() échoue. Serveur : getServerSession().
4. Cookie / domaine
localhost:3000 vs example.com — mauvais domaine, session perdue. NEXTAUTH_URL correct en prod, pas de hardcode localhost.
5. JWEDecryptionFailed
NEXTAUTH_SECRET changé, ancien token dans le navigateur. Supprimer les cookies ou se reconnecter.
Bonus : protéger des routes avec Middleware
middleware.ts :
export { default } from "next-auth/middleware"
export const config = {
matcher: ["/dashboard/:path*", "/profile/:path*"]
}
/dashboard et /profile exigent une connexion.
Recommandations projet et suite
Quelle solution choisir ?
Scénario 1 : projet perso / MVP / blog
- Recommandation : NextAuth.js + JWT + Credentials
- Pourquoi : gratuit, simple, pas de table session
- Inconvénient : migration si besoin de « kick » plus tard
Scénario 2 : entreprise / SaaS (avec budget)
- Recommandation : Clerk
- Pourquoi : rapide, belle UI, gestion utilisateurs — économise 40–80 h de dev
- Inconvénient : coût au-delà de 10 000 MAU
- Note : avec Supabase, Supabase Auth (50 000 MAU en gratuit)
Scénario 3 : entreprise (sans budget / contrôle total)
- Recommandation : NextAuth.js + Database Session + OAuth
- Pourquoi : gratuit, sessions révocables
- Inconvénient : UI et base à maintenir
Scénario 4 : système utilisateurs existant
- Recommandation : NextAuth.js + Credentials + JWT
- Pourquoi : flexible, structure DB inchangée
- Attention : sécurité (hash, brute-force) à votre charge
Ressources
- Options de configuration NextAuth.js
- Credentials Provider
- Session Strategies
- Learn Next.js – authentification (CN)
- Tutoriel JWT NextAuth.js
- Discussion Credentials + DB session
- FAQ NextAuth.js
- NextAuth vs Clerk vs Supabase
Conclusion
Trois décisions :
- Méthode de login ? Credentials ou OAuth — souvent OAuth (Google/GitHub) est plus simple
- Stockage session ? JWT ou Database — perso → JWT, entreprise → Database
- Validation ? Credentials = votre logique ; OAuth = le fournisseur
Commencez par l’exemple minimal de cet article — connectez-vous d’abord, enrichissez ensuite.
NextAuth.js a une courbe d’apprentissage ; une fois maîtrisé, vous contrôlez tout le flux. Pour aller vite : Clerk. Pour économiser et apprendre : NextAuth.js.
À lire ensuite :
-
Guide complet Next.js Middleware (protection de routes, A/B tests)
-
RBAC : voir notre article sur la conception des permissions
Configuration complète du login Credentials avec NextAuth.js
De l'installation à la mise en place du login par identifiant/mot de passe et de la gestion des sessions
⏱️ Estimated time: 2 hr
- 1
Step 1: Installer et initialiser NextAuth.js
Installer les dépendances :
• npm install next-auth
• Créer app/api/auth/[...nextauth]/route.ts
Configuration de base :
• Définir NEXTAUTH_URL (local : http://localhost:3000)
• Définir NEXTAUTH_SECRET (chaîne aléatoire)
• Configurer le tableau providers - 2
Step 2: Configurer le Credentials Provider
Implémenter la logique de validation :
1. Valider l'utilisateur dans authorize de CredentialsProvider
2. Interroger la base (ou utilisateur de test en dur)
3. Vérifier le mot de passe (bcrypt, etc.)
4. Retourner l'objet utilisateur (id, name, email, etc.)
Attention :
• authorize doit retourner un objet utilisateur ou null
• L'objet retourné est stocké dans la session
• La vérification du mot de passe doit être côté serveur - 3
Step 3: Choisir la stratégie de session (JWT ou Session)
Stratégie JWT (par défaut) :
• Adaptée aux apps sans état
• Infos de session dans le token JWT
• Pas de base de données requise
• Config : session: { strategy: 'jwt' }
Stratégie Session (base requise) :
• Adaptée si vous devez révoquer des connexions
• Infos en base de données
• Adapter nécessaire (Prisma, MongoDB, etc.)
• Config : session: { strategy: 'database' } - 4
Step 4: Configurer les callbacks pour personnaliser le flux
Callbacks courants :
• signIn : autoriser ou refuser la connexion
• jwt : personnaliser le contenu du JWT (stratégie JWT)
• session : personnaliser le contenu de la session
Exemple :
callbacks: {
async jwt({ token, user }) {
if (user) token.role = user.role
return token
},
async session({ session, token }) {
session.user.role = token.role
return session
}
} - 5
Step 5: Créer la page de connexion et les composants
API NextAuth.js :
• signIn('credentials', { username, password }) : déclencher la connexion
• signOut() : se déconnecter
• useSession() : récupérer la session courante
• SessionProvider : envelopper l'app pour le contexte de session
Exemple :
const { data: session } = useSession()
if (session) {
return <div>Connecté : {session.user.name}</div>
} - 6
Step 6: Tester et déboguer
Points de test :
• Identifiants corrects → connexion OK
• Mauvais identifiants → refus
• Persistance de la session
• Déconnexion efface la session
Débogage :
• Console navigateur
• Logs serveur
• Mode debug NextAuth.js
• Vérifier les variables d'environnement
FAQ
Quelle différence entre NextAuth.js, Clerk et Supabase Auth ?
• Solution open source auto-hébergée, entièrement gratuite
• UI de connexion et gestion utilisateurs à implémenter vous-même
• Mais contrôle total
Clerk :
• UI et interface d'administration complètes
• Payant au-delà de 10 000 utilisateurs actifs mensuels
Supabase Auth :
• Idéal si vous utilisez la base Supabase
• Intégration simple mais couplage à la base
JWT ou Session : que choisir ?
Le login Credentials est-il sécurisé ?
1) Stocker les mots de passe chiffrés (bcrypt, etc.)
2) Valider côté serveur
3) Utiliser HTTPS
4) Exiger une politique de mot de passe
5) Envisager un captcha anti brute-force
Comment personnaliser la page de connexion ?
Créez ensuite votre page et appelez signIn('credentials', { username, password }).
Vous pouvez aussi construire toute l'UI vous-même en n'utilisant que l'API NextAuth.js.
Comment obtenir l'utilisateur connecté ?
const { data: session } = useSession()
Côté serveur : getServerSession() :
const session = await getServerSession(authOptions)
L'objet session contient user (id, name, email, etc.).
Comment gérer rôles et permissions ?
Quelles bases NextAuth.js prend-il en charge ?
10 min de lecture · Publié le: 19 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide complet Next.js
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Optimisation des performances React Server Components : récupération de données et cache en pratique
Guide pratique d'optimisation RSC : du problème de waterfall au streaming, stratégies de récupération de données et de cache. Parcours TTFB 450 ms→45 ms, 4 solutions comparées et 5 API de cache.
Partie 47 sur 51
Suivant
JWT ou Session ? Arrêtez de tergiverser — après cet article, vous saurez quoi choisir
Hésitez entre JWT et Session ? Comparaison pratique des deux stratégies de session : config NextAuth.js, performance et sécurité pour prendre la bonne décision.
Partie 49 sur 51



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire