Décodeur de Tokens JWT
Décode les JSON Web Tokens et visualise leur contenu.
Decoding only — the signature is not verified. Nothing is sent anywhere.
Vue d’ensemble
Un JWT est composé de trois parties encodées en base64url et séparées par des points : un en-tête indiquant comment il a été signé, une charge utile de revendications, et une signature portant sur les deux premières. L’encodage n’est pas du chiffrement. Quiconque détient le jeton peut lire chacune de ses revendications, ce qu’il vaut mieux avoir intériorisé avant de placer quoi que ce soit dans une charge utile.
Cet outil décode les deux premières parties et les met en forme, puis extrait les trois revendications temporelles et les convertit de secondes Unix en horodatages lisibles. Il ne vérifie pas la signature — voir plus bas pourquoi c’est le bon choix et non une fonctionnalité manquante.
Utilisation
- Collez le jeton. Tout ce qui suit
Bearer— le schéma lui-même ne fait pas partie du JWT. - Lisez l’en-tête pour voir l’algorithme et, s’il est présent, l’identifiant de clé.
- Lisez la charge utile pour les revendications.
- Consultez le tableau des horodatages pour
iat,nbf,expet le verdict d’expiration.
Les revendications enregistrées
| Revendication | Nom | Remarques |
|---|---|---|
iss | Émetteur | Qui a émis le jeton. Votre serveur devrait le comparer à une liste d’émetteurs autorisés |
sub | Sujet | De qui parle le jeton. En général un identifiant utilisateur stable, pas une adresse e-mail |
aud | Audience | Pour qui le jeton a été émis. Un jeton émis pour une autre audience doit être rejeté |
exp | Expiration | Secondes Unix. Passé cet instant, rejeter |
nbf | Pas avant | Secondes Unix. Avant cet instant, rejeter |
iat | Émis à | Secondes Unix. Utile pour « réauthentifier si plus ancien que N » |
jti | Identifiant du JWT | Identifiant unique, pour révoquer un jeton ou contrôler les rejeux |
Les sept sont optionnelles dans la spécification. Un jeton dépourvu d’exp
n’expire jamais de lui-même, ce qui est un choix de conception à remarquer quand
on le rencontre.
Pourquoi la vérification de signature n’est pas proposée
Vérifier une signature exige la clé : le secret partagé pour HS256, ou la clé
publique pour RS256 et ES256. Dans le cas symétrique, la clé qui vérifie est
aussi celle qui signe — une page proposant la vérification vous demanderait donc
de coller l’identifiant qui permet à n’importe qui d’émettre des jetons pour votre
système. Il n’existe aucune version de cela qu’il soit sûr de construire.
Le décodage vaut malgré tout la peine. L’essentiel du débogage de JWT consiste à
répondre à « que dit vraiment ce jeton » — mauvaise audience, portée manquante,
un exp cinq minutes dans le passé, un sub qui est une adresse e-mail alors que
votre code attend un UUID. Tout cela est visible sans la clé.
Ce que le décodage ne peut pas vous dire, c’est si le jeton est authentique. Un JWT que vous recevez est une affirmation, pas un fait, jusqu’à ce que votre serveur vérifie la signature avec une clé en laquelle il a confiance.
Le champ alg n’est pas une décision que votre vérificateur doit déléguer
Le champ alg de l’en-tête décrit ce que l’expéditeur a utilisé. Un
vérificateur qui lit alg et choisit son algorithme en conséquence fait confiance
à une entrée contrôlée par l’attaquant, ce qui produit deux ruptures classiques :
alg: none. Le JWT non sécurisé est légal dans la spécification. Un vérificateur qui l’honore accepte n’importe quelle charge utile accompagnée d’une signature vide.RS256échangé contreHS256. Si une bibliothèque prend la clé publique et l’utilise comme secret HMAC, un attaquant qui connaît votre clé publique — elle est publique — peut signer des jetons que vous accepterez.
Les deux sont des problèmes de configuration, pas de cryptographie. Fixez l’algorithme attendu dans votre vérificateur et rejetez tout le reste, au lieu de le lire dans le jeton.
Exemples
- Un 401 que vous n’expliquez pas. Décodez et vérifiez
aud. Un jeton émis pour une API et présenté à une autre est la cause la plus fréquente, et le message d’erreur le dit rarement. - Un 401 intermittent. Comparez
expàiat. Une durée de vie courte plus un client qui met le jeton en cache est intermittent par construction. - Une permission qui devrait fonctionner. Cherchez
scopeourolesdans la charge utile. Si la revendication est absente, le problème est chez l’émetteur, pas dans votre code d’autorisation. - Auditer ce que vous mettez dans un jeton. Décodez l’un des vôtres. Tout ce qui s’y trouve — adresse e-mail, identifiants internes, drapeaux de fonctionnalité — est lisible par quiconque détient le jeton, y compris par le navigateur qui le stocke.
Où un jeton doit vivre dans un navigateur
La question revient chaque fois que quelqu’un décode un jeton et constate qu’il est lisible. En résumé : puisqu’un JWT est un identifiant porteur, tout ce qui peut le lire peut l’utiliser.
localStorage est lisible par n’importe quel script de l’origine, ce qui signifie
qu’une XSS emporte le jeton avec elle. Il n’est jamais envoyé automatiquement, en
revanche, donc on ne peut pas vous attaquer en CSRF par ce biais — vous échangez
une classe de bugs contre une autre.
Un cookie HttpOnly ne peut pas être lu par un script du tout, donc une XSS ne
peut pas le voler. Il est envoyé automatiquement, il lui faut donc
SameSite=Lax ou Strict en plus de Secure, et tout point d’entrée qui modifie
un état a besoin de sa propre défense contre le CSRF.
La conclusion habituelle pour une application de navigateur est un jeton d’accès à
durée de vie courte conservé uniquement en mémoire, renouvelé depuis un cookie de
jeton de rafraîchissement HttpOnly, Secure, SameSite. Ainsi une XSS obtient
un jeton qui vit quelques minutes plutôt qu’un identifiant valable des semaines, et
le secret à longue durée de vie n’est jamais atteignable depuis JavaScript.
Quel que soit votre choix, c’est exp qui fait le vrai travail. Un jeton d’une
heure de durée de vie sans liste de révocation reste valable une heure après son
vol, et rien du côté client n’y change quoi que ce soit.
Remarques
Le remplissage est ajouté avant le décodage, parce que le base64url l’omet normalement. Les jetons copiés depuis des journaux arrivent parfois avec leur remplissage intact, et les deux formes fonctionnent ici.
Le verdict d’expiration utilise votre horloge locale : c’est donc une commodité
plutôt qu’une autorité. Si vous devez comparer à un instant précis, utilisez le
convertisseur d’horodatage Unix sur la valeur brute d’exp.
Les charges utiles ne sont pas toujours du JSON en principe — la spécification autorise n’importe quel type de contenu — mais tous les JWT rencontrés en pratique transportent un objet JSON, et une charge utile qui n’arrive pas à s’analyser comme du JSON est affichée en texte brut plutôt que masquée.