Authentification et sécurité API Next.js : guide complet du JWT au rate limiting

Le téléphone vibre — alerte de facture du cloud provider : 7 800 dollars.
Je frotte les yeux, je crois mal lire. Le mois dernier : 120 dollars. Je consulte le détail : 18 millions d’appels API. Mon projet perso tourne habituellement à quelques centaines d’appels par jour.
Un crawler avait trouvé mon endpoint API sans aucune protection et avait bombardé pendant trois jours. Ce jour-là, j’ai compris pourquoi on dit que la sécurité API n’est pas optionnelle.
Cet article rassemble les pièges que j’ai rencontrés et les solutions étudiées. De l’authentification JWT à la configuration CORS, du rate limiting à la validation des entrées — pas de théorie creuse, mais du code prêt à l’emploi.
Pourquoi la sécurité API est si importante
Menaces courantes sur les API
En décembre dernier, React a publié un avis de sécurité critique, CVE-2025-55182, score CVSS au maximum — 10.0.
Qu’est-ce que ça signifie ? Le score le plus élevé. Un attaquant peut exécuter du code arbitraire sur votre serveur avec une requête HTTP spécialement construite. Si vous utilisez React Server Components sans mise à jour, vous êtes exposé.
Ce n’est pas un cas isolé. En mars, une faille de contournement d’autorisation (CVE-2025-29927), score 9.1. L’attaquant forge un en-tête de requête et contourne votre middleware d’authentification. Vous pensiez être protégé ? Il passe directement.
Au-delà de ces vulnérabilités critiques, les menaces quotidiennes sont plus nombreuses :
Crawlers malveillants et attaques DDoS. Sans rate limiting, une API peut s’effondrer en minutes. J’ai vu des endpoints de login recevoir 3 000 requêtes par seconde — brute force, serveur à l’arrêt.
Fuites de données. Sans contrôle d’accès, l’utilisateur A voit les commandes de l’utilisateur B. Une fois dans les médias, la réputation de la marque est ruinée.
Injections. SQL injection, XSS, injection de commandes… ça sonne dépassé, mais des milliers de projets en souffrent chaque année. Vous pensez « React échappe automatiquement », mais sans validation côté API, ça ne suffit pas.
Spécificités des API Routes Next.js
Les API Routes Next.js diffèrent d’un backend traditionnel :
Serverless first. Sur Vercel, chaque requête API est une fonction Serverless indépendante. Avantage : scaling automatique. Inconvénient : sans état — pas de Session en mémoire, il faut JWT ou Session en base.
Mélangé avec le frontend. Tout dans un même dépôt ; les variables d’environnement peuvent fuiter côté client. J’ai vu quelqu’un mettre DATABASE_URL dans .env et l’exposer dans le bundle frontend sur GitHub.
Limites de l’edge computing. Avec Edge Runtime, certaines API Node.js sont indisponibles ; bibliothèques crypto et connexions DB à repenser. Les solutions de sécurité suivent.
En bref, l’API Next.js est votre backend — plus léger, plus flexible, et plus facile à mal configurer.
Authentification API en pratique
Guide de choix du schéma d’authentification
Question concrète : JWT ou Session ?
Au début de mes projets Next.js, j’hésitais aussi. JWT « moderne obligatoire » d’un côté, Session « plus sûr » de l’autre. En pratique, ça dépend du contexte.
JWT convient quand :
- Déploiement multi-serveurs (Serverless, edge)
- Authentification cross-domain (frontend sur app.com, API sur api.com)
- Pas envie de gérer le stockage de Session — simplicité
JWT encode les infos utilisateur dans un token ; le serveur ne stocke rien, chaque requête apporte le token. Scaling horizontal très simple.
Session convient quand :
- Contrôle actif côté serveur (révoquer une session, changement de permissions en temps réel)
- Sécurité maximale, aucune info utilisateur côté client
- Redis ou base déjà en place pour gérer les Sessions
La Session vit côté serveur ; le client n’a qu’un Session ID. Pour invalider un utilisateur, supprimez la Session — impossible avec JWT.
Mon critère : petits projets perso → JWT, simple ; enterprise avec contrôle fin → Session. Ne vous bloquez pas, commencez avec l’un, changez si besoin.
Implémentation complète JWT
Supposons que vous choisissez JWT. Comment l’implémenter dans Next.js ?
Étape 1 : générer et vérifier le Token
Installez une bibliothèque :
npm install jose
Pourquoi pas jsonwebtoken ? Pas compatible Edge Runtime. jose suit les standards Web, fonctionne partout.
Créez lib/auth.ts :
import { SignJWT, jwtVerify } from 'jose';
const secret = new TextEncoder().encode(
process.env.JWT_SECRET || 'your-secret-key-at-least-32-characters'
);
export async function createToken(payload: { userId: string }) {
return new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('15m') // expire après 15 minutes
.sign(secret);
}
export async function verifyToken(token: string) {
try {
const { payload } = await jwtVerify(token, secret);
return payload;
} catch {
return null;
}
}
Notez l’expiration 15m. Beaucoup mettent 7 ou 30 jours — pratique, mais si le token fuite, l’attaquant l’utilise longtemps. Access Token court + Refresh Token long : la bonne approche.
Étape 2 : stocker le Token — pas localStorage
Point crucial. Beaucoup de tutos mettent le token dans localStorage ; une attaque XSS vole tout.
Bonne pratique : cookie HttpOnly.
À la connexion :
// app/api/login/route.ts
import { NextResponse } from 'next/server';
import { createToken } from '@/lib/auth';
export async function POST(request: Request) {
// Vérifier identifiants...
const token = await createToken({ userId: user.id });
const response = NextResponse.json({ success: true });
response.cookies.set('token', token, {
httpOnly: true, // illisible en JS, anti-XSS
secure: true, // HTTPS uniquement
sameSite: 'lax', // anti-CSRF
maxAge: 900, // 15 min, aligné sur l'expiration du token
});
return response;
}
HttpOnly est la clé : JavaScript ne lit pas ce cookie, XSS ne peut pas le voler.
Étape 3 : middleware pour protéger l’API
Token en place — comment exiger la connexion sur certaines API ? Middleware Next.js.
Créez middleware.ts :
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { verifyToken } from './lib/auth';
export async function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value;
if (!token) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
const payload = await verifyToken(token);
if (!payload) {
return NextResponse.json(
{ error: 'Invalid token' },
{ status: 401 }
);
}
// Validé : transmettre l'utilisateur à l'API
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-user-id', payload.userId as string);
return NextResponse.next({
request: {
headers: requestHeaders,
},
});
}
export const config = {
matcher: '/api/protected/:path*',
};
Toutes les routes /api/protected/* sont protégées. Dans l’API, récupérez l’utilisateur :
// app/api/protected/profile/route.ts
import { headers } from 'next/headers';
export async function GET() {
const headersList = await headers();
const userId = headersList.get('x-user-id');
// Charger l'utilisateur depuis la base...
}
Étape 4 : mécanisme de rafraîchissement du Token
15 minutes, l’utilisateur se reconnecte sans cesse ? Introduisez le Refresh Token.
Access Token court (15 min), Refresh Token long (30 jours). Access Token expiré → échangez avec Refresh Token, pas de nouvelle connexion.
L’implémentation est un peu plus complexe ; next-auth intègre cette logique.
Intégration rapide avec NextAuth.js
Franchement, tout coder soi-même aide à comprendre, mais c’est lourd. Pour démarrer vite : NextAuth.js (maintenant Auth.js).
Points forts : sécurité par défaut prête à l’emploi :
- Protection CSRF automatique
- Signature et chiffrement de Session
- JWT et Session en base
- OAuth Google, GitHub, etc.
Installation :
npm install next-auth
Créez 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: "Email", type: "email" },
password: { label: "Password", type: "password" }
},
async authorize(credentials) {
// Vérifier identifiants...
if (user) {
return { id: user.id, email: user.email };
}
return null;
}
})
],
session: {
strategy: 'jwt', // JWT, adapté au Serverless
maxAge: 30 * 24 * 60 * 60, // 30 jours
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.userId = user.id;
}
return token;
},
async session({ session, token }) {
session.userId = token.userId;
return session;
}
}
});
export { handler as GET, handler as POST };
Puis vérifiez la session dans l’API :
import { getServerSession } from 'next-auth';
export async function GET() {
const session = await getServerSession();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Session OK, traiter la requête...
}
Simple. NextAuth gère tokens et rafraîchissement de Session.
Configuration CORS détaillée
Essence du CORS et problèmes courants
CORS (Cross-Origin Resource Sharing) embête beaucoup de monde. En dev tout va, en prod :
Access to fetch at 'https://api.example.com' from origin 'https://app.example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.
En bref, le navigateur interdit à la page A d’accéder aux ressources de B. Sur app.com, vous appelez api.com : le navigateur demande à api.com « app.com est autorisé ? » L’API doit répondre oui.
Pourquoi pas d’erreur en dev ?
Next.js en dev : frontend et API sur localhost:3000, même origine. En prod, frontend sur Vercel, API ailleurs → cross-domain.
C’est quoi une requête Preflight ?
Un POST avec en-têtes custom (ex. Authorization) déclenche d’abord une OPTIONS. C’est le Preflight. Sans handler OPTIONS → 404 → échec CORS.
J’ai déjà oublié OPTIONS : POST OK, CORS en échec, longue recherche.
Trois méthodes pour configurer CORS dans Next.js
Méthode 1 : next.config.js global
Quand toutes les API partagent les mêmes origines autorisées.
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/api/:path*',
headers: [
{ key: 'Access-Control-Allow-Origin', value: 'https://app.example.com' },
{ key: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,DELETE' },
{ key: 'Access-Control-Allow-Headers', value: 'Content-Type, Authorization' },
],
},
];
},
};
Avantage : une fois pour toutes. Inconvénient : peu flexible par route.
Méthode 2 : Middleware
Pour jugement dynamique et traitement unifié.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Requête Preflight
if (request.method === 'OPTIONS') {
return new NextResponse(null, {
status: 200,
headers: {
'Access-Control-Allow-Origin': 'https://app.example.com',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
});
}
// Requête normale : en-têtes CORS
const response = NextResponse.next();
response.headers.set('Access-Control-Allow-Origin', 'https://app.example.com');
return response;
}
export const config = {
matcher: '/api/:path*',
};
Accès à l’objet request pour autoriser selon l’origine.
Méthode 3 : dans la API Route
Pour une API avec des règles spécifiques.
// app/api/public/route.ts
import { NextResponse } from 'next/server';
export async function GET() {
const data = { message: 'Hello' };
return NextResponse.json(data, {
headers: {
'Access-Control-Allow-Origin': '*', // API publique, toutes origines
},
});
}
export async function OPTIONS() {
return new NextResponse(null, {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Content-Type',
},
});
}
Chaque API doit gérer OPTIONS, sinon Preflight échoue.
Bonnes pratiques CORS
1. N’abusez pas du wildcard
Beaucoup écrivent :
'Access-Control-Allow-Origin': '*'
Tout site peut appeler votre API. OK pour données publiques ; pour infos utilisateur ou actions sensibles, c’est une exposition totale.
Bonne pratique : domaines explicites.
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];
const origin = request.headers.get('origin');
if (origin && allowedOrigins.includes(origin)) {
response.headers.set('Access-Control-Allow-Origin', origin);
}
2. Attention aux credentials
Si l’API lit les cookies (Session), côté frontend :
fetch('https://api.example.com', {
credentials: 'include',
});
Côté backend :
response.headers.set('Access-Control-Allow-Credentials', 'true');
Mais Access-Control-Allow-Origin ne peut pas être * — le navigateur refuse. Domaine précis obligatoire.
3. Gérer Preflight
Requêtes avec Authorization ou Content-Type: application/json déclenchent souvent Preflight. Répondez à OPTIONS.
Fonction utilitaire :
export function corsHeaders(origin?: string) {
return {
'Access-Control-Allow-Origin': origin || 'https://app.example.com',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400', // cache Preflight 24 h
};
}
Réutilisez dans chaque API.
Rate limiting API
Pourquoi le rate limiting
Retour à l’histoire du début. 18 millions d’appels — avec un plafond de 100 req/min/IP, la perte aurait été de quelques dizaines de dollars, pas 7 800.
Le rate limiting limite le nombre d’appels API par unité de temps. Simple et efficace :
Anti-DDoS. Trop de requêtes ? Au-delà du seuil, refus — le serveur tient.
Anti brute force. Login sans limite : 10 000 mots de passe/seconde. Avec 5 tentatives/min/IP, la difficulté explose.
Protection des ressources. DB et APIs tierces coûtent cher. Le rate limiting évite qu’un utilisateur épuise tout.
Comparaison des solutions
Option 1 : @upstash/ratelimit + Vercel KV
Ma solution habituelle. Upstash = Redis Serverless, partenaire Vercel, intégration simple.
Avantages :
- Compatible Serverless, pas de serveur Redis à gérer
- Algorithmes : fenêtre fixe, glissante, token bucket
- Quota gratuit suffisant pour projets perso
Inconvénients :
- Payant à gros volume
- Dépendance tierce
Option 2 : Redis self-hosted
Si vous avez déjà Redis ou refusez le tiers.
Avantages :
- Contrôle total, pas de surcoût
- Logique custom possible
Inconvénients :
- Maintenance Redis
- Config complexe en Serverless
Option 3 : rate limiting en mémoire
Sans Redis, limite simple en mémoire.
Avantages :
- Zéro dépendance, quelques lignes
- Dev et petits projets
Inconvénients :
- Serverless : instances différentes, mémoire non partagée → limite inefficace
- Redémarrage = données perdues
Conseil : perso/Serverless → Upstash ; enterprise avec serveurs → Redis ; demo/local → mémoire.
Exemple de code
Avec Upstash, pas à pas.
Étape 1 : installation et config
npm install @upstash/ratelimit @upstash/redis
Créez une base Redis sur Upstash, mettez UPSTASH_REDIS_REST_URL et UPSTASH_REDIS_REST_TOKEN dans .env :
UPSTASH_REDIS_REST_URL=https://xxx.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-token
Étape 2 : créer le limiteur
Créez lib/rate-limit.ts :
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
// Client Redis
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
// Limiteur : fenêtre glissante, max 10 req / 10 s
export const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(10, '10 s'),
analytics: true,
});
slidingWindow(10, '10 s') : max 10 requêtes en 10 s. Fenêtre glissante plus lisse que fixe.
Étape 3 : utiliser dans l’API
// app/api/protected/route.ts
import { NextResponse } from 'next/server';
import { ratelimit } from '@/lib/rate-limit';
export async function GET(request: Request) {
// IP client
const ip = request.headers.get('x-forwarded-for') || 'unknown';
// Vérifier le rate limit
const { success, limit, remaining, reset } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json(
{
error: 'Too many requests',
limit,
remaining,
reset: new Date(reset),
},
{
status: 429,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': reset.toString(),
},
}
);
}
// Sous la limite, traiter normalement
return NextResponse.json({ data: 'Success' });
}
IP comme identifiant. Avec login, utilisez userId :
const identifier = session?.userId || ip;
const { success } = await ratelimit.limit(identifier);
Utilisateur connecté → par user ; anonyme → par IP.
Étape 4 : rate limiting global en Middleware
// middleware.ts
import { ratelimit } from '@/lib/rate-limit';
export async function middleware(request: NextRequest) {
const ip = request.ip || 'unknown';
const { success } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
);
}
return NextResponse.next();
}
export const config = {
matcher: '/api/:path*',
};
Toutes les API protégées d’un coup.
Validation des entrées et défense
Pourquoi la validation est la première ligne
« Ne jamais faire confiance aux entrées utilisateur » — règle d’or de la sécurité.
Validation frontend ? Inutile seule. DevTools, code modifié, validation contournée. La vraie défense est côté serveur.
Injection SQL. '; DROP TABLE users; -- concaténé dans du SQL → catastrophe. ORM partout, mais SQL natif existe encore.
XSS. <script>alert('hacked')</script> stocké → exécution chez d’autres, cookies volés. React échappe, sauf avec dangerouslySetInnerHTML.
DoS. JSON de 10 Mo → mémoire Serverless saturée. Chaîne énorme → regex qui ne finit jamais.
La validation bloque la plupart des attaques basiques. Sans elle, le reste est une passoire.
Validation type-safe avec Zod
Zod est ma bibliothèque préférée. TypeScript natif, parfait avec le système de types.
npm install zod
Usage de base
Définissez un schema :
import { z } from 'zod';
const userSchema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Password must be at least 8 characters'),
age: z.number().int().min(18).max(120),
});
Dans l’API :
// app/api/register/route.ts
import { NextResponse } from 'next/server';
import { userSchema } from '@/lib/schemas';
export async function POST(request: Request) {
const body = await request.json();
// Valider les données
const result = userSchema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{
error: 'Validation failed',
details: result.error.format(),
},
{ status: 400 }
);
}
// Validé : données typées
const { email, password, age } = result.data;
// Suite du traitement...
}
Préférez safeParse (pas d’exception). parse lève une erreur.
Pourquoi mieux que la validation manuelle ?
Manuel :
if (!body.email || typeof body.email !== 'string') {
return error;
}
if (!body.email.includes('@')) {
return error;
}
// des dizaines de lignes...
Zod :
z.string().email()
Une ligne, types inférés.
Schéma complet de validation
Au-delà des types : logique métier et cas limites.
1. Valider le body
const postSchema = z.object({
title: z.string().min(1).max(100),
content: z.string().max(10000), // limite de taille
tags: z.array(z.string()).max(10), // limite du tableau
publishedAt: z.string().datetime().optional(),
});
2. Valider les query params
// app/api/posts/route.ts
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const querySchema = z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
sort: z.enum(['asc', 'desc']).default('desc'),
});
const params = querySchema.parse({
page: searchParams.get('page'),
limit: searchParams.get('limit'),
sort: searchParams.get('sort'),
});
// params.page est un number typé
}
z.coerce.number() convertit les strings en nombres.
3. Règles custom
const passwordSchema = z.string()
.min(8)
.refine((val) => /[A-Z]/.test(val), 'Must contain uppercase')
.refine((val) => /[a-z]/.test(val), 'Must contain lowercase')
.refine((val) => /[0-9]/.test(val), 'Must contain number');
Validation async :
const emailSchema = z.string().email().refine(
async (email) => {
const exists = await checkEmailExists(email);
return !exists;
},
'Email already taken'
);
4. Gestion des erreurs
if (!result.success) {
const errors = result.error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
return NextResponse.json({ errors }, { status: 400 });
}
Erreurs structurées, faciles à afficher côté frontend.
Autres mesures de sécurité
1. Protection CSRF
Les Server Actions Next.js comparent Origin et Host. API Routes : à faire vous-même. NextAuth le gère ; sinon token CSRF :
// Token CSRF en cookie, envoyé par le frontend, vérifié côté serveur
2. Content Security Policy (CSP)
Dans next.config.js, limitez les ressources chargées :
{
headers: [
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self'; style-src 'self';",
},
],
}
Même avec XSS, scripts malveillants bloqués.
3. Sécurité des variables d’environnement
Next.js distingue :
NEXT_PUBLIC_*→ exposé au frontend- sans préfixe → serveur uniquement
Ne mettez jamais de secrets dans NEXT_PUBLIC_. J’ai vu NEXT_PUBLIC_API_KEY en prod.
4. Protection injection SQL
Prisma, Drizzle : requêtes paramétrées automatiques.
SQL natif :
// ❌ dangereux
db.query(`SELECT * FROM users WHERE id = ${userId}`);
// ✅ sûr
db.query('SELECT * FROM users WHERE id = ?', [userId]);
5. Mettre à jour les dépendances
npm audit
npm update
La faille React de février : mise à jour = corrigé. Ne remettez pas à plus tard.
Checklist sécurité complète
Authentification
- ✅ Token dans cookie HttpOnly, pas localStorage
- ✅ Access Token ≤ 30 minutes
- ✅ Mécanisme Refresh Token
- ✅ Clé JWT ≥ 32 caractères, en variable d’environnement
- ✅ Cookie
secureetsameSite - ✅ Middleware sur API sensibles
CORS
- ✅ Pas de
Access-Control-Allow-Origin: *sur API sensibles - ✅ Liste de domaines autorisés explicite
- ✅ OPTIONS Preflight géré
- ✅
Access-Control-Allow-Credentials: truesi credentials - ✅ Vérifier CORS en production
Rate limiting
- ✅ Limite stricte sur login, register, reset password
- ✅ Stratégies différentes utilisateur authentifié / anonyme
- ✅ 429 et en-tête
Retry-After - ✅ Redis ou Upstash (pas mémoire seule en Serverless)
- ✅ Surveiller les déclenchements, ajuster les seuils
Validation des entrées
- ✅ Toutes les entrées validées côté serveur
- ✅ Zod ou équivalent type-safe
- ✅ Limites de taille string, array, object
- ✅ Formats (email, URL, date)
- ✅ Messages d’erreur clairs
Audit régulier
- ✅
npm auditmensuel, corriger les critiques - ✅ Next.js et React à jour
- ✅ Suivre les avis de sécurité Next.js
- ✅ Revue des variables d’environnement
- ✅ Code review auth et permissions
Imprimez la checklist : avant un nouveau projet, avant chaque déploiement.
Conclusion
En une phrase : la sécurité API est un système, pas un réglage unique.
Auth, CORS, rate limiting, validation — ça prend du temps à configurer. Après une fuite, un serveur down ou une facture astronomique, le coût de rattrapage est bien plus élevé.
Mon expérience : mise en place initiale, une demi-journée à une journée. Ensuite, copier-coller et adapter — nouveau projet en une quinzaine de minutes. Surtout : dormir tranquille.
Actions :
- Auditez vos projets avec la checklist
- Commencez par l’essentiel : auth et rate limiting
- Suivez l’actualité sécurité : blog Next.js, GitHub Security Advisories
- Partagez avec l’équipe — la sécurité concerne tout le monde
Dernière remarque : la faille React CVSS 10.0 de décembre 2025 touche énormément de projets. Pas encore à jour ? Mettez à jour maintenant. Les correctifs de sécurité ne attendent pas.
Le chemin de la sécurité API est long, chaque pas compte. J’espère que cet article vous évitera quelques pièges.
FAQ
Faut-il utiliser JWT ou Session pour les API Next.js ?
Pourquoi ne pas stocker le JWT token dans localStorage ?
Pourquoi pas d'erreur CORS en dev mais oui en production ?
Comment implémenter le rate limiting en environnement Serverless ?
Comment empêcher le brute force des mots de passe sur l'API ?
15 min de lecture · Publié le: 5 janv. 2026 · 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
Guide complet d'optimisation des performances API Next.js : cache, streaming et edge computing
Réponse API Next.js de 3 s à 500 ms ? Stratégies de cache, réponses en streaming et Edge Functions avec exemples de code réels et données de performance pour booster vos API dès maintenant.
Partie 19 sur 51
Suivant
Application de chat temps réel Next.js : WebSocket et SSE, la bonne approche
Comparaison approfondie de WebSocket, SSE et Long Polling pour la communication temps réel, retour d'expérience Vercel, exemples complets pour Socket.io, gestion des états de message et optimisation des performances.
Partie 21 sur 51



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire