Ce qu’est vraiment un JWT
Un JSON Web Token est une chaîne de caractères. Toute l’astuce est là. Au lieu de donner au client un identifiant de session et de garder la session sur le serveur, vous lui remettez une affirmation signée — « voici l’utilisateur 4821, voici ses droits, cela expire à 14h05 » — et vous le laissez la transporter. Tout service qui fait confiance à la clé de signature peut lire l’affirmation et agir sans interroger de base de données.
C’est ce qui rend les JWT très pratiques et un peu dangereux, pour la même raison : les données sont entre les mains du client. Un token que vous émettez est lisible par quiconque le détient, ne peut pas être retiré avant son expiration, et sera accepté par tout ce qui fait confiance à la signature. Presque tous les problèmes de JWT en production viennent de l’oubli d’un de ces trois faits.
Un token ressemble à trois blocs illisibles séparés par des points :
eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleS0yIn0.eyJzdWIiOiI0ODIxIiwiZXhwIjoxNzY1MTExMTExfQ.3xS7_c9Nn-aQ
Il n’est pas chiffré. Les deux premiers blocs sont du JSON en Base64url, un alphabet compatible
URL qui remplace + et / par - et _ et supprime
le remplissage final en =. N’importe qui peut les retransformer en JSON en une
seconde, et c’est exactement ce que fait un décodeur JWT.
Les trois parties, et le rôle de chacune
Coupez le token aux points et vous obtenez l’en-tête, la charge utile et la signature.
L’en-tête
Court, et presque toujours une affaire de clés. alg nomme l’algorithme de
signature, typ vaut généralement JWT, et kid est un
identifiant de clé qui indique au vérificateur quelle clé publique récupérer quand l’émetteur en a
plusieurs. Si un token cesse brusquement d’être validé après une rotation de clés, regardez
kid en premier.
La charge utile
Les claims : l’affirmation réellement faite. Certains sont enregistrés par la spécification
(iss, sub, aud, exp, nbf,
iat, jti) et le reste est ce que votre émetteur a décidé d’ajouter :
scope, roles, tenant_id, une adresse e-mail, un indicateur
de fonctionnalité.
La signature
Un MAC ou une signature numérique portant sur les deux premières parties, telles qu’elles apparaissent dans la chaîne. Ce détail compte : la signature couvre les octets encodés, donc re-sérialiser le JSON puis le ré-encoder produit un token qui ne se valide plus, même si les données sont identiques. Ne reconstruisez jamais un token pour le « mettre au propre ».
Comment décoder un token, et quoi regarder d’abord
Collez la chaîne entière dans un décodeur, points compris. Si vous l’avez copiée depuis une
requête, retirez le préfixe Bearer — ou utilisez un outil qui le retire pour vous.
Puis lisez dans cet ordre :
- Est-ce que ça a décodé ? Si le décodeur annonce que les parties ne sont pas du JSON Base64url valide, le token est arrivé tronqué ou abîmé. Un cookie qui a atteint une limite de taille et un en-tête coupé en lignes ressemblent à cela.
exp. L’expiration explique la majorité des « ça marchait il y a cinq minutes », et c’est la première chose à écarter.audetiss. Un token émis pour une autre audience est un token parfaitement valide que votre API a raison de refuser.- Les claims personnalisés. Ce n’est qu’une fois les claims standard vérifiés
qu’il vaut la peine de discuter du contenu de
scope.
Décodez en local autant que possible. Un token est un identifiant actif : le coller sur un site quelconque est la même catégorie d’erreur que coller un mot de passe. Tout outil qui mérite votre confiance décode dans le navigateur et n’envoie rien nulle part.
Les claims qui décident si un token fonctionne
Cinq claims font presque tout le travail, et chacun peut refuser une requête à lui seul.
exp— l’expiration, en timestamp Unix en secondes. Une valeur en millisecondes est un bug classique : elle tombe en l’an 57000 et le token n’expire jamais. Un bon décodeur affiche à la fois la date réelle et le temps écoulé.nbf— not before. Le token est invalide avant cet instant. Rarement utilisé volontairement, parfois posé par accident sur une machine dont l’horloge avance.iat— émis le. Utile pour refuser des tokens techniquement non expirés mais suspectement vieux, et pour repérer un problème d’horloge quandiatest dans le futur.aud— l’audience, le destinataire prévu. Une API qui saute cette vérification acceptera volontiers un token qu’un autre de vos services a émis pour lui-même, et c’est un véritable chemin d’élévation de privilèges entre microservices.iss— l’émetteur. Épinglez l’émetteur exact attendu et ne récupérez les clés que dans le jeu de clés publié par cet émetteur.
jti est le cas à part : un identifiant unique de token. Il ne signifie quelque
chose que si vous le stockez et le vérifiez, mais c’est lui qui rend possible la révocation d’un
seul token.
Décoder n’est pas vérifier
C’est le point qui piège. Décoder lit le Base64url et vous montre le JSON. Cela vous dit ce que le token affirme. Cela ne dit rien sur la véracité de cette affirmation.
N’importe qui peut écrire {"sub":"1","role":"admin"}, l’encoder en Base64url,
coller n’importe quelle chaîne en guise de signature et vous le remettre. Il se décodera
parfaitement dans n’importe quel décodeur, y compris le nôtre. Ce qui l’empêche de fonctionner,
c’est l’étape de vérification : recalculer la signature avec la clé de l’émetteur et refuser le
token s’il ne correspond pas. Cette étape exige un secret ou une clé publique, elle appartient à
votre serveur, et aucun outil de navigateur ne peut la faire à votre place.
Traitez donc un décodeur comme un relevé, jamais comme une preuve. « Je l’ai décodé et il dit admin » n’est pas un constat de sécurité. « Mon serveur l’a vérifié et il dit admin », oui.
Pourquoi un token d’apparence valide reçoit un 401
Quand le token se décode proprement et que l’API le refuse quand même, c’est presque toujours l’une de ces causes :
- Expiré. Comparez
expà l’horloge du serveur, pas à la vôtre. - Décalage d’horloge. Un serveur en avance de deux minutes refusera des tokens tout juste émis. La plupart des bibliothèques autorisent une petite tolérance précisément pour cela ; si la vôtre est à zéro, cela vaut la peine d’y revenir.
- Mauvaise audience. Fréquent quand un fournisseur d’identité sert plusieurs API.
- Rotation de clés. L’émetteur a signé avec une nouvelle clé, le vérificateur a
encore l’ancien jeu en cache, et
kidne résout plus. - Le token n’est jamais arrivé. Un en-tête
Authorizationabsent ou mal formé, un cookie perdu, ou un proxy qui supprime des en-têtes. Vérifiez ce que le serveur a réellement reçu avant d’accuser le token : la recherche de codes de statut HTTP et notre guide des codes de statut aident à distinguer un 401 d’un 403 qui veut dire tout autre chose.
401 ou 403 ?
Un 401 signifie que l’identifiant manque, a expiré ou n’est pas vérifiable :
corrigez le token. Un 403 signifie que l’identifiant était bon et que la réponse reste
non : corrigez les permissions, ou le claim scope. Les services qui renvoient 401 pour
un échec d’autorisation envoient les gens déboguer un token qui n’a jamais été le problème.
Choisir et vérifier l’algorithme de signature
Deux familles comptent en pratique. HS256 est un HMAC à secret partagé : qui peut vérifier peut aussi signer, ce qui convient à l’intérieur d’un service et mal entre organisations. RS256 et ES256 signent avec une clé privée et se vérifient avec une clé publique, de sorte qu’une API peut valider des tokens qu’elle n’aurait jamais pu émettre.
Et puis il y a alg: none, un token non signé que la spécification autorise et que
vous ne devez jamais accepter. Il existe dans la norme, donc il a existé dans les bibliothèques,
donc il a été exploité : à un vérificateur qui prend l’algorithme dans l’en-tête du token lui-même,
on peut dire « celui-ci n’est pas signé, fais confiance ». Une variante
remet à un vérificateur RS256 un token HS256 signé en utilisant la clé publique comme secret
HMAC.
La défense tient en une ligne de politique : décidez quels algorithmes vous acceptez
avant de regarder le token, et refusez tout le reste. L’en-tête est une indication sur la
clé à utiliser, pas une instruction sur l’opportunité de vérifier la signature. Si votre décodeur
signale alg: none en rouge, c’est pour cela.
Ce qui ne doit jamais figurer dans une charge utile
Comme la charge utile est encodée et non chiffrée, chaque claim est public pour quiconque détient le token — et les tokens finissent dans le stockage du navigateur, dans les journaux, dans les traqueurs d’erreurs, dans les tickets de support et sur des captures d’écran. Gardez hors de la charge utile :
- Tout ce que vous ne mettriez pas dans une URL : mots de passe, clés d’API, numéros de carte, données de santé.
- Les identifiants internes que vous préférez ne pas publier : clés primaires de base de données, noms d’hôtes internes, conditions de licence.
- Les gros blocs. Chaque requête transporte le token ; un kilo-octet de claims, c’est un kilo-octet à chaque appel, et les tokens surdimensionnés sont un bon moyen d’atteindre les limites de taille d’en-tête d’un proxy.
Gardez aussi les tokens hors des URL. Un token dans une chaîne de requête se retrouve dans les
journaux du serveur, dans les en-têtes Referer et dans l’historique du navigateur.
Envoyez-le dans l’en-tête Authorization, et assurez-vous que votre site définit un
Referrer-Policy raisonnable : notre guide des en-têtes de sécurité traite le sujet, et le
vérificateur d’en-têtes de sécurité vous
dira ce que vous envoyez aujourd’hui.
Expiration, rafraîchissement et le problème de la révocation
Un JWT ne peut pas être rappelé. Une fois émis, il est valide jusqu’à exp, quoi
qu’il arrive au compte derrière. Désactivez un utilisateur : son token d’accès continue de
fonctionner jusqu’à épuisement. C’est le prix de ne pas interroger une base de données à chaque
requête.
La réponse habituelle, ce sont deux tokens. Un token d’accès à courte durée — des minutes, pas des jours — porte les claims et fait le travail. Un token de rafraîchissement à longue durée est stocké côté serveur, vérifié en base à chaque utilisation, et révocable instantanément. Déconnecter quelqu’un revient alors à invalider le token de rafraîchissement et à attendre la courte fenêtre avant que le token d’accès meure de lui-même.
Choisissez la fenêtre d’expiration délibérément : c’est l’écart entre la révocation de l’accès
et l’arrêt effectif de l’accès. Quinze minutes est un compromis courant. Des heures sont difficiles
à justifier ; des jours signifient que vous n’avez aucune révocation. Et s’il vous faut une
révocation immédiate, tenez une liste de refus de valeurs jti — auquel cas vous
interrogez de nouveau un stockage à chaque requête, et une simple session est peut-être le design
le plus simple.
Quel que soit votre choix, la boucle de débogage est la même : décodez le token, lisez
exp et aud, confirmez l’horloge, puis vérifiez la signature sur le
serveur. Quatre étapes, dans cet ordre, et presque tous les problèmes de token tombent dans les
deux premières.
Outils et guides associés :
- Décodeur JWT : Décodez un JSON Web Token et lisez son en-tête, sa charge utile, ses claims et son expiration.
- Encodeur et décodeur Base64 : Encodez du texte en Base64 ou décodez-le, avec sortie URL-safe et UTF-8 géré.
- Base64 expliqué : comment l’encodage et le décodage fonctionnent : Comment Base64 transforme des octets en texte
Questions fréquentes
Puis-je décoder un JWT sans la clé secrète ?⌄
Oui. L’en-tête et la charge utile sont encodés en Base64url, pas chiffrés : quiconque détient le token peut les lire. La clé ne sert qu’à vérifier la signature. C’est aussi pourquoi il ne faut jamais placer de données sensibles dans une charge utile.
Est-il sûr de coller un JWT dans un décodeur en ligne ?⌄
Seulement si le décodage a lieu dans votre navigateur. Un token est un identifiant actif jusqu’à son expiration, donc un outil qui l’envoie à un serveur manipule votre identifiant. Notre décodeur fonctionne entièrement dans la page et n’envoie le token nulle part, mais la meilleure habitude reste d’utiliser des tokens expirés ou de test quand c’est possible.
Pourquoi mon token se décode-t-il bien tout en renvoyant un 401 ?⌄
Le décodage prouve seulement que la chaîne est bien formée. Les coupables habituels sont un exp déjà passé, un écart d’horloge entre l’émetteur et le vérificateur, un aud qui désigne une autre API, ou un kid que le vérificateur ne peut plus résoudre après une rotation de clés.
Quelle différence entre un JWT et un cookie de session ?⌄
Un cookie de session est un pointeur : le serveur garde l’état et le consulte à chaque requête, donc il peut être révoqué instantanément. Un JWT transporte l’état lui-même, donc aucune consultation n’est nécessaire — et rien ne peut être retiré avant expiration. Les JWT passent mieux à l’échelle entre services ; les sessions vous donnent le contrôle.
Faut-il utiliser HS256 ou RS256 ?⌄
HS256 partage un seul secret : qui peut vérifier peut aussi signer. C’est acceptable à l’intérieur d’un service unique. RS256 et ES256 signent avec une clé privée et se vérifient avec une clé publique, ce que vous voulez dès que plusieurs parties sont impliquées. Dans tous les cas, fixez les algorithmes acceptés dans votre vérificateur et ne faites jamais confiance à la valeur alg du token.
Plus de 15 ans d'expérience pratique en développement web et en sécurité. Spécialisé dans la sécurité web concrète : garder les sites sûrs, fiables et faciles à diagnostiquer. BuildToolForge existe pour rendre ces vérifications gratuites, privées et compréhensibles. Les outils s'exécutent dans votre navigateur dès que possible, et rien de ce que vous saisissez dans un outil n'est conservé.
Comment nous rédigeons nos guides : Chaque guide s'appuie sur une expérience de terrain, est vérifié par rapport aux normes officielles et testé avec nos propres outils sur de vrais domaines. Nous mettons les guides à jour quand les normes ou les outils évoluent. Une erreur ? Écrivez-nous à contact@buildtoolforge.com.