Aller au contenu principal

JWT vs sessions

Les sessions gardent la vérité côté serveur : un token opaque de 16–32 octets indexe un magasin que vous contrôlez, donc la révocation est immédiate et bon marché. Les JWT portent la vérité dans le token lui-même — signé, sans état, vérifiable partout — mais la révocation signifie attendre que l’expiration passe. Utilisez les sessions pour les connexions d’une application unique ; les JWT quand de nombreux services doivent vérifier une identité sans magasin partagé.

100 % local

JWT vs sessions en clair

Les deux conceptions résolvent le même problème : les requêtes HTTP arrivent sans mémoire, donc chacune a besoin de quelque chose qui dit « c’est bien la personne qui s’est connectée ». Une session classique remet au client un token opaque — une chaîne aléatoire qui pointe vers un état côté serveur. Un JWT (RFC 7519) remet au client l’état lui-même : un ensemble signé de claims que le serveur vérifie sans rien consulter. L’un range la vérité sur le serveur ; l’autre la notarie et l’expédie avec la requête.

Cette différence — l’endroit où vit la vérité — se propage à chaque arbitrage de la page. Un JWT se vérifie par un contrôle de signature, donc tout service détenant la clé peut authentifier une requête sans magasin partagé ; le prix, c’est que le token reste valable jusqu’à son claim exp, si bien que « déconnectez maintenant » et « bannissez cet utilisateur maintenant » n’ont aucune implémentation naturelle. Un token de session ne vaut rien sans son magasin, donc la révocation est une suppression — mais chaque service qui vérifie doit atteindre ce magasin.

Aucun camp n’est en train de gagner, et les systèmes matures font couramment tourner les deux — cookies de session opaques pour l’application face aux humains, JWT à courte durée de vie entre services. Les sections ci-dessous comparent révocation, stockage, taille et surface d’attaque ; le décodeur relié tout au long de la page vous laisse inspecter de vrais tokens sans rien envoyer.

Avant de faire confiance à n’importe quel token en production, dépliez-en un avec le décodeur JWT — il décode en-tête et charge utile en local et ne demande jamais de clé.

Pour une anatomie segment par segment, le guide de structure JWT passe en revue en-tête, charge utile et signature avec des exemples réels.

Deux formes, deux philosophies

Une session serveur est un pointeur. Le token — 16 à 32 octets aléatoires, généralement posé en cookie — ne porte aucun sens ; tout le sens vit dans le magasin : Redis, une base de données, voire la mémoire du processus. Cette indirection est la fonctionnalité. L’enregistrement peut contenir n’importe quoi, tout changer ou disparaître, et les clients ne s’en aperçoivent jamais, ne détenant qu’un pointeur.

Un JWT est une déclaration. Trois segments base64url — en-tête, charge utile, signature — portent les claims : sub pour l’utilisateur, iss pour l’émetteur, exp pour l’expiration, plus des claims personnalisés. La signature (HMAC avec un secret partagé, ou RSA/ECDSA avec une paire de clés) prouve que la déclaration est intacte et vient d’un détenteur de clé. Vérifier ne demande aucune consultation ; faire confiance ne demande que la clé.

Révocation : l’arbitrage qui départage la plupart des projets

Avec les sessions, « déconnexion » et « bannissement d’utilisateur » sont des opérations sur le magasin : supprimez l’enregistrement, et la requête suivante échoue. Avec les JWT, le token reste cryptographiquement valable jusqu’à exp, quel que soit le vœu du serveur émetteur — l’intérêt du sans-état, c’est que la vérification ne refait jamais le chemin en arrière. Les parades sont bien connues et toutes réintroduisent de l’état : expiration courte avec rotation des refresh tokens, listes de révocation sur jti, ou un claim de version incrémenté à la déconnexion. Chacune reconstruit une part du magasin dont vous vous étiez passé.

Le cadrage honnête : les sessions rendent la révocation gratuite mais facturent une consultation du magasin à chaque requête ; les JWT en font une décision de conception que vous payez au moment de la déconnexion. Si « déconnecter partout, immédiatement » est une exigence, les sessions ou une rotation étroitement gérée sont dans votre avenir.

Stockage et surface d’attaque : cookies, localStorage, XSS et CSRF

L’endroit où vit le token compte autant que ce qu’il est. Un JWT garé dans localStorage est lisible par chaque script de la page, si bien qu’une seule faille XSS exfiltre une information d’authentification de type bearer valable jusqu’à expiration — sans aucun moyen côté serveur de la révoquer. Un token opaque dans un cookie HttpOnly, Secure, SameSite est invisible pour JavaScript, ce qui plafonne le rayon d’impact de la XSS ; le coût, c’est l’exposition au CSRF — le navigateur attache le cookie automatiquement — atténuée par SameSite et des tokens CSRF.

Les JWT peuvent voyager en cookies aussi (et souvent le devraient), avec les mêmes réserves CSRF ; un en-tête Authorization esquive le CSRF mais replace le token à portée de JavaScript. Aucun arrangement de stockage n’est sûr face à la XSS — seuls des arrangements qui limitent ce que l’attaquant peut dérober.

Taille, et ce qu’un JWT révèle réellement

Un JWT de connexion type mesure 800 octets ou plus avec quelques claims, et chaque requête le répète — alors que les cookies plafonnent autour de 4 KB par domaine. Un token de session opaque reste à 16–32 octets quoi qu’il arrive. À grande échelle, la différence se voit dans les en-têtes, les proxys et les logs.

La charge utile est en base64url — encodage, pas chiffrement — donc quiconque détient le token peut lire chaque claim, données personnelles et permissions comprises. JWE existe pour les tokens chiffrés et n’est presque jamais utilisé. Collez un vrai token dans le décodeur ci-dessous : en-tête et charge utile se déplient dans votre navigateur, la signature est affichée mais jamais vérifiée — la vérification exige la clé secrète, que l’outil ne demande jamais.

AspectSession serveurJWT (RFC 7519)
Où vit la véritéMagasin côté serveurDans le token signé
RévocationImmédiate — supprimer l’enregistrementÀ exp, ou via un état ajouté
Taille du token16–32 octets opaques~800 B+ avec des claims typiques
Coût de vérificationConsultation du magasin par requêteContrôle de signature, sans consultation
Authentification multi-servicesMagasin de sessions partagé requisTout service détenant la clé
ExpirationTTL côté serveur, modifiableClaim exp, figé à l’émission
Stockage navigateurCookie HttpOnly + SameSiteCookie, ou localStorage (risque XSS)

Quand choisir l’un ou l’autre

Choisissez les sessions quand une seule application porte la connexion : sites rendus côté serveur, panneaux d’administration, tout ce où déconnexion immédiate et gestion des appareils valent une consultation de Redis. Choisissez les JWT quand la vérification doit se produire en de nombreux endroits — microservices, applications mobiles, services entre équipes — et qu’un magasin de sessions partagé pour tous est le coût le plus lourd.

La recommandation s’inverse proprement. Dès que vous bâtissez un service de liste de révocation ou de rotation pour rendre les JWT révocables, demandez-vous si un magasin de sessions ne s’est pas infiltré ; dès qu’un magasin de sessions fait goulot d’étranglement pour une douzaine de services, demandez-vous si des JWT à courte durée de vie entre eux seraient plus légers. Les hybrides — un cookie opaque pour le navigateur, des JWT de service à service — ne sont pas un compromis ; ils sont l’état final normal.

Questions fréquentes

Puis-je décoder un JWT ici sans l’envoyer ni le transmettre où que ce soit ?

Oui. Le décodeur s’exécute entièrement dans votre navigateur : en-tête et charge utile sont du base64url simple, donc ils se déplient en local sans qu’aucune requête ne quitte l’onglet — la Content-Security-Policy du site bloque les appels sortants. La signature est affichée pour inspection mais jamais vérifiée : la vérification exige la clé de signature, que l’outil ne demande jamais.

Un JWT est-il chiffré ?

Non. La RFC 7519 définit un token signé : la charge utile est en base64url — lisible par quiconque le détient — et la signature prouve seulement qui l’a émis et qu’il n’a pas été altéré. Le chiffrement est un profil distinct (JWE) que les systèmes réels utilisent rarement. Considérez chaque claim comme public : identifiants et rôles conviennent ; secrets et données personnelles non.

Comment révoquer un JWT immédiatement ?

Impossible avec le token seul — c’est l’échange du sans-état. Les systèmes réels rajoutent de l’état : fenêtres exp courtes avec rotation des refresh tokens pour que les tokens volés meurent vite, une liste de révocation indexée sur le claim jti, ou un claim de version de token incrémenté à la déconnexion. Les trois sont un magasin de sessions avec des étapes en plus.

Les cookies HttpOnly sont-ils plus sûrs que localStorage pour les tokens ?

Face à la XSS, oui. localStorage est lisible par chaque script de la page, donc une seule injection vole un token bearer valable jusqu’à expiration ; un cookie HttpOnly est invisible pour JavaScript, donc la même injection ne peut pas s’en emparer. Le coût du cookie, c’est le CSRF, traité avec SameSite et des tokens CSRF. HttpOnly ne vainc pas la XSS — il retire le token du butin.

Pourquoi les microservices préfèrent-ils les JWT aux sessions ?

Parce que la vérification devient locale. Avec RS256, chaque service détient la clé publique et valide les tokens sans appel à un magasin de sessions partagé ; un nouveau service démarre avec une clé, pas une intégration. Les sessions opaques mettent chaque service à la merci de la disponibilité d’un seul magasin. Cette indépendance est le gain du sans-état — et la révocation en est la facture.

Jusqu’à quelle taille un JWT devient-il un problème ?

Surveillez d’abord les cookies : les navigateurs les plafonnent autour de 4 KB par domaine, et un JWT riche en claims peut s’en approcher et casser des requêtes net. Même sous le plafond, un token de ~800 octets voyage dans chaque requête, tandis qu’un token de session opaque reste à 16–32 octets quoi qu’il arrive. Gardez des claims maigres : identité et expiration, pas des données de profil.

Où puis-je lire les normes citées ici ?