Un JSON Web Token, ce sont trois blocs Base64url réunis par des points : un en-tête, une charge utile et une signature. Cet outil les sépare et vous montre ce qu'ils contiennent. Il ne vérifie pas la signature, et cette omission est délibérée — la raison mérite deux minutes de votre temps.
Décoder n'est pas vérifier
Ce sont deux opérations totalement différentes, et les confondre provoque des incidents de sécurité. Décoder ne demande rien : l'en-tête et la charge utile sont encodés en Base64url, pas chiffrés — quiconque détient le jeton lit chacun de ses claims. Vérifier exige la clé de signature et répond à une autre question : ce jeton a-t-il vraiment été émis par celui qu'il prétend, et quelqu'un l'a-t-il modifié depuis ?
Un outil qui lit un jeton ne prouve rien quant à sa validité. Collez ici un jeton expiré et vous en verrez tout de même le contenu parfaitement affiché. Le fait que le décodage réussisse vous dit que la chaîne est bien formée, rien de plus.
Pourquoi cet outil refuse de vérifier les signatures
Beaucoup de sites consacrés aux JWT proposent une case pour votre secret de signature à côté du jeton. Réfléchissez à ce qu'on vous demande. En HS256, le secret est la clé même qui fabrique des jetons valides : confiez-le à une page web, et celui qui exploite cette page peut désormais forger n'importe quel jeton pour votre système. Il n'existe aucun moyen de vérifier une signature symétrique sans céder du même coup la capacité d'en créer.
Cet outil ne le demande donc pas, et méfiez-vous de ceux qui le font. Vérifiez les signatures dans votre propre code, dans votre propre environnement d'exécution, avec la clé chargée depuis votre propre coffre à secrets. Une clé de signature a sa place à exactement deux endroits : le service qui émet les jetons et celui qui les contrôle.
Les claims sur lesquels on trébuche
Les horodatages sont les coupables habituels. La RFC 7519 définit exp, iat et nbf comme des NumericDate : des secondes depuis l'époque Unix. Le Date.now() de JavaScript renvoie des millisecondes. Passer l'un là où l'autre est attendu est le bug JWT le plus répandu qui soit : un jeton qui expire en 1970, ou qui reste valide les cinquante mille prochaines années. Si un exp décodé affiche une date dans un passé lointain ou un futur absurde, vous avez trouvé un facteur 1000.
L'autre surprise fréquente est nbf, « not before ». Un jeton peut être parfaitement signé, non expiré, et malgré tout rejeté parce qu'il n'est pas encore valide — le symptôme d'un décalage d'horloge entre la machine émettrice et la machine validatrice, plutôt que d'un défaut du jeton.
Le champ alg est une instruction, pas une description
L'en-tête porte un claim « alg » qui nomme l'algorithme de signature, et la vulnérabilité JWT classique est une bibliothèque qui lui fait confiance. Si un validateur lit alg dans le jeton puis vérifie en conséquence, un attaquant peut mettre alg à « none », retirer la signature et entrer : c'est le jeton lui-même qui a dit au validateur de ne pas vérifier.
L'attaque apparentée échange RS256 contre HS256. En RS256, le jeton est signé avec une clé privée et vérifié avec la publique. Un validateur naïf qui lit alg comme HS256 utilisera cette clé publique comme secret HMAC — et la clé publique est, par définition, publique. Ces deux attaques sont anciennes et les bibliothèques maintenues refusent aujourd'hui les valeurs d'alg que l'appelant n'a pas explicitement autorisées. Si vous regardez un jeton dont l'en-tête indique « none », soit vous testez quelque chose, soit vous regardez une attaque.
Ce qu'il ne faut pas mettre dans une charge utile
Puisque la charge utile est lisible par quiconque détient le jeton, ce n'est pas un endroit pour quoi que ce soit de privé. Pas de notes internes sur l'utilisateur, pas de logique de permissions que vous préféreriez ne pas avoir à expliquer, pas de données personnelles au-delà de ce dont le jeton a besoin pour faire son travail. La signature empêche la modification, pas la lecture — une distinction qui a mis dans l'embarras bien des équipes persuadées qu'un jeton signé était un jeton scellé.
Questions fréquentes
Mon jeton est-il envoyé à un serveur ?
Non. Cet outil porte la mention « client » : la découpe et le décodage se font dans votre onglet et le jeton ne quitte jamais votre machine. Mais l'habitude mérite d'être questionnée en général — un JWT est un identifiant vivant. Si vous avez collé un jeton de production dans un site web quelconque, celui-ci compris, l'hypothèse la plus sûre est qu'il doit être renouvelé.
Puis-je vérifier si ce jeton est valide ?
Pas ici, ni sur aucun site que vous n'exploitez pas vous-même — voyez la section ci-dessus. Ce que vous pouvez constater à l'œil, c'est si le jeton a expiré, puisque exp figure directement dans la charge utile décodée. Cela couvre la raison la plus fréquente pour laquelle un jeton cesse de fonctionner, sans qu'aucune clé ne change de mains.
Pourquoi l'expiration s'affiche-t-elle en 1970 ?
Parce qu'un horodatage en millisecondes est lu comme s'il était en secondes. Divisez par 1000 et la date redeviendra cohérente. Ce qui a produit le jeton utilise Date.now() là où la RFC 7519 attend Math.floor(Date.now() / 1000).
Puis-je modifier un jeton et le resigner ici ?
Non. Changer un seul caractère de la charge utile invalide la signature, et en produire une nouvelle valide exige la clé de signature — qui, comme vu plus haut, n'est pas quelque chose à coller dans une page web. Modifier des jetons se fait dans votre propre suite de tests, avec une clé de test.
Le jeton a des points mais ne se décode pas. Pourquoi ?
Le plus souvent, ce n'est pas un JWT. Les jetons chiffrés (JWE) comptent cinq segments au lieu de trois, et leur charge utile est réellement illisible sans la clé. L'autre cause fréquente est la troncature : les jetons sont longs et se font couper par les formateurs de journaux, la largeur des terminaux et les cellules de tableur. Si le segment du milieu s'arrête net, il vous manque probablement des caractères plutôt que d'avoir affaire à un jeton malformé.