JWT encode/decode : fabriquer et inspecter un token en ligne

JWT encode/decode : fabriquer et inspecter un token en ligne

Décodez l'en-tête et le payload d'un JWT ou signez un token de test dans votre navigateur : HS256, RS256, ES256, sans envoyer de secret à un tiers.

04.10.2026
18 min de lecture
Partager cet article:
JWT
Authentification
Tokens
Sécurité
Tutoriel

Un JWT est lisible par tous : décoder pour inspecter, signer pour tester, vérifier pour faire confiance

Un JSON Web Token a l'air opaque, mais ses deux premiers segments sont du JSON ordinaire encodé en Base64URL : quiconque détient le token peut le lire. C'est exactement ce qu'il vous faut quand une API répond 401 et que vous voulez savoir ce que le token affirme. Le décodeur JWT en ligne de FastMinify décode l'en-tête et le payload dès que vous collez le token, et l'encodeur JWT signe un token à partir d'un en-tête et d'un payload JSON modifiables, en direct, sans bouton d'envoi. Les deux tournent dans votre navigateur : le token, les claims et le secret ne partent nulle part. Décoder n'est pourtant pas vérifier. N'importe qui peut écrire "role": "admin" dans un payload : ce que dit un token décodé ne prouve rien sur celui qui l'a émis. Contrôler une signature avec les clés publiques d'un émetteur, l'audience, l'émetteur et l'expiration, c'est le rôle de jwt-verify, qui prend un JWKS collé, et inspect-jwks montre ce que contient un tel jeu de clés. Ce guide explique comment un JWT est construit, comment déboguer un 401 ou un 403 avec un token décodé, les erreurs qui transforment un outil de test en faille de sécurité, et les mêmes opérations en Node avec la bibliothèque jose. Les outils se trouvent sur le hub des outils sécurité.

Décodage : collez le token compact et l'en-tête et le payload s'affichent en JSON formaté. Un JWT comporte exactement trois parties séparées par des points ; la signature ne peut être vide que si l'en-tête indique alg=none
Encodage : signature en direct, sans bouton d'envoi. Algorithmes : none, HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512 et EdDSA (Ed25519 uniquement)
À l'encodage, iat est toujours réécrit à l'heure actuelle. Le menu Expiration (Aucune, 15 minutes, 1 heure, 24 heures) écrase exp par rapport à iat ; « Aucune » laisse votre payload tel quel
Les tokens HMAC prennent un secret (lu éventuellement comme des octets Base64URL) ; RSA, ECDSA et EdDSA prennent une clé privée PEM (PKCS#8) ou JWK
Vérification de signature optionnelle à côté du décodeur, avec un secret ou une clé publique : elle contrôle la signature seule, jamais exp, aud ou iss
Tout reste dans l'onglet : aucun token, claim ou clé n'est envoyé à un serveur

Encoder, décoder ou vérifier : quel outil répond à quelle question

Usages adaptés

Le décodeur et l'encodeur couvrent tout ce qui n'exige pas d'établir la confiance envers un émetteur.

Lire les claims d'un token copié depuis l'onglet Réseau (exp, aud, scope) avant d'incriminer une route d'API
Fabriquer un token de fixture pour un test d'intégration : HS256, un secret jetable, une expiration de 15 minutes ou d'1 heure
Produire un token avec un en-tête précis (alg, kid) pour voir comment votre API le rejette
Vérifier qu'un token HS256 a bien été signé avec le secret que vous croyez : collez le secret à côté du décodeur
Enseigner ou apprendre le format compact : modifiez un caractère du payload et regardez le segment de signature changer
Ce qui relève d'un autre outil

Faire confiance à un token demande des clés, des claims et une politique, pas seulement un payload lisible. Passez la main à jwt-verify, à inspect-jwks ou à votre propre code.

Vérifier un token avec les clés publiques d'un fournisseur d'identité : collez le JWKS dans <a href="/fr/jwt-verify" class="text-primary hover:underline">jwt-verify</a>, qui contrôle la signature, l'expiration, l'audience et l'émetteur, avec une tolérance d'horloge de 0, 60 ou 300 secondes. Il ne récupère jamais un JWKS sur le réseau
Voir quelles clés contient un JWKS (kid, kty, alg) avant de déboguer un « key not found » : <a href="/fr/inspect-jwks" class="text-primary hover:underline">inspect-jwks</a>
Émettre et valider des tokens en production : une bibliothèque maintenue côté serveur, avec l'algorithme imposé. Jamais une page web
Révoquer une session : un JWT signé reste valide jusqu'à exp par lui-même, c'est une question de conception de votre flux d'authentification, hors de portée de tout décodeur
Stocker des mots de passe d'utilisateurs : un hash lent et salé, pas un JWT. Voir le <a href="/fr/blog/generer-mot-de-passe-securise-en-ligne" class="text-primary hover:underline">guide du générateur de mot de passe</a> et l'<a href="/fr/bcrypt-hash" class="text-primary hover:underline">outil bcrypt</a>

Déboguer un 401 ou un 403 avec un token décodé

401 : expiré, pas encore valide ou abîmé

Collez le token dans le décodeur et lisez les claims de temps avant de toucher à l'API. exp, nbf et iat sont des NumericDate : des secondes depuis le 1er janvier 1970 UTC (RFC 7519).

Un exp à 13 chiffres est en millisecondes, pas en secondes : le producteur se trompe, et beaucoup de bibliothèques le liront comme une date située à des dizaines de milliers d'années
Convertissez la valeur dans une console : <code>new Date(exp * 1000).toISOString()</code>. Le décodeur affiche le nombre brut et ne le convertit pas à votre place
Soustrayez iat de exp : le résultat est la durée de vie du token en secondes (3600 pour une heure). Une durée de 0 ou négative pointe une mauvaise configuration de l'émetteur
Un nbf dans le futur, ou un iat en avance sur l'horloge de l'API, signale un décalage d'horloge entre émetteur et API : les serveurs acceptent en général une petite tolérance, et jwt-verify permet de tester 0, 60 et 300 secondes
Collez uniquement le token compact. Un préfixe <code>Bearer </code>, un saut de ligne ou un caractère coupé par un log fait signaler au décodeur un token invalide ou un mauvais nombre de parties
401 sur un token qui a l'air correct : algorithme, clé et signature

Quand les claims sont bons et que l'API refuse quand même, le problème se trouve dans l'en-tête ou la signature.

alg dans l'en-tête doit être celui que l'API attend. Une API figée sur RS256 rejette un token HS256, et inversement
kid désigne une clé du jeu de clés de l'émetteur : ouvrez le JWKS dans <a href="/fr/inspect-jwks" class="text-primary hover:underline">inspect-jwks</a> et vérifiez qu'elle existe, et que son alg et son kty correspondent
Collez le secret HMAC à côté du décodeur : « Signature invalide » avec un secret qui semble juste signifie le plus souvent que l'option Base64URL est mauvaise (voir plus bas) ou que le token a été altéré en route
Un token à cinq parties séparées par des points est un JWE chiffré, pas un JWT signé. Le décodeur le rejette, car il attend exactement trois parties
Un token copié depuis un cookie ou un en-tête peut être tronqué par une limite de taille : un dernier segment manquant en est le symptôme typique
403 : authentifié, mais pas autorisé

Un 403 signifie que le token a été accepté et que l'étape d'autorisation a dit non. Le payload dit généralement pourquoi.

aud doit contenir l'identifiant que l'API attend, et iss doit correspondre à l'émetteur de confiance. Un token émis pour une autre API ou un autre tenant échoue ici
Les permissions se trouvent sous des noms de claims différents selon le fournisseur : scope, scp, roles ou permissions. Vérifiez celui que votre API lit réellement
Une chaîne scope est séparée par des espaces (<code>"orders:read orders:write"</code>), alors que des rôles sont souvent un tableau : un code qui découpe l'un comme l'autre refuse tout, sans bruit
sub identifie l'utilisateur, pas l'application : un token de service à service peut y porter un identifiant client
Une permission tout juste modifiée n'est pas dans un token émis avant le changement : décodez un token récent avant de conclure que la règle est fausse

Quatre erreurs qui transforment un outil de test en faille de sécurité

Traiter un token décodé comme un token de confiance

Un décodeur montre ce qu'un token affirme, pas qui l'a écrit. Le payload n'est pas protégé : quiconque a le token, ou peut en fabriquer un, peut y mettre n'importe quel claim. L'encodeur peut même produire un token non sécurisé avec alg=none, dont le segment de signature est vide : les outils l'étiquettent « JWT non signé (alg=none) », et aucun vérificateur ne devrait jamais l'accepter. La RFC 8725 (bonnes pratiques JWT) demande aux serveurs de n'accepter que les algorithmes attendus et de ne jamais laisser le token choisir. La confusion d'algorithme est la défaillance classique : un token qui déclare HS256 et qui est signé avec la clé publique d'un service RS256 passe chez un vérificateur qui lit alg dans l'en-tête et utilise la clé publique comme secret HMAC.

Lire <code>"role": "admin"</code> dans un payload décodé comme la preuve que l'utilisateur est administrateur
Accepter l'alg que déclare l'en-tête du token, none compris
Décider des autorisations dans un front à partir de claims jamais vérifiés
Prendre le « Signature vérifiée » d'un décodeur pour un substitut aux contrôles d'audience, d'émetteur et d'expiration
Croire que le payload est secret

Base64URL est un encodage, pas un chiffrement : le guide Base64 explique la différence. Un JWT signé (JWS) garantit seulement l'intégrité, donc tout le payload est lisible. Il existe des tokens chiffrés (JWE, RFC 7516, cinq parties au lieu de trois), mais le décodeur d'ici ne traite que les tokens signés. Un token est aussi un identifiant d'accès : qui le détient peut l'utiliser jusqu'à exp. Cet outil le garde dans votre onglet, mais un partage d'écran, une capture partagée ou un ticket collé avec le token le divulgue quand même.

Mettre un mot de passe, un numéro de carte ou une adresse personnelle dans un claim
Coller un token de production encore valide dans un ticket, une messagerie ou un site tiers
Journaliser l'en-tête Authorization en entier
Supposer qu'un token à l'aspect illisible est un token protégé
Des secrets HMAC faibles ou mal lus

HS256 signe avec un secret partagé, et la RFC 7518 demande une clé au moins aussi longue que la sortie du hash : 256 bits pour HS256, 384 pour HS384, 512 pour HS512. Quand votre secret est plus court, l'encodeur affiche sa taille en bits face au minimum recommandé. Ce chiffre est la longueur de la clé, pas son caractère aléatoire : une phrase de 32 caractères en français fait 256 bits de long et reste devinable. Un attaquant qui détient un seul token peut tester des secrets candidats hors ligne contre sa signature, sans jamais toucher votre API. Tirez le secret au hasard, par exemple avec le générateur de mot de passe (voir le guide mot de passe) : environ 41 caractères de son jeu par défaut de 82 caractères portent 256 bits d'entropie. L'option Base64URL change les octets utilisés : cochée, la chaîne du secret est décodée en Base64URL et ses octets forment la clé ; décochée, ce sont les caractères eux-mêmes. Le même texte avec le mauvais réglage donne une autre signature.

Utiliser <code>secret</code>, <code>changeme</code> ou le nom du projet comme clé HS256
Lire « 256 bits de long » comme « 256 bits d'entropie »
Signer avec l'option Base64URL activée et vérifier avec elle désactivée, ou l'inverse
Partager un même secret HMAC entre des services qui ne devraient pas tous pouvoir émettre des tokens
Laisser un token de test sortir du test

L'encodeur est conçu pour les fixtures et le débogage. Il réécrit iat à maintenant, peut supprimer entièrement la signature, et les exemples qu'il charge utilisent des secrets jetables. Un token signé ici avec un secret de démonstration ne doit jamais être accepté par un environnement réel, et un vrai secret de signature ne doit jamais être collé dans un fichier que vous commitez ensuite. Si c'est déjà arrivé, changez-le, et scannez votre diff avant de commiter avec le scanner de secrets.

Commiter un token de test à longue durée dont le secret fonctionne aussi en préproduction
Garder un raccourci alg=none « pour le dev local » derrière un drapeau qui part en production
Réutiliser le même secret de signature en développement, préproduction et production
Oublier qu'un exp réglé à 24 heures dans une fixture reste un identifiant d'accès pendant 24 heures

Anatomie d'un JWT : trois segments Base64URL et ce que chacun dit

header.payload.signature

La forme compacte, ce sont trois segments Base64URL joints par des points. C'est ce qui voyage dans un en-tête Authorization: Bearer.

En-tête : un objet JSON comme <code>{"alg":"HS256","typ":"JWT"}</code>, qui s'encode en <code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</code>. Il nomme l'algorithme de signature et, pour les clés asymétriques, en général un kid.
Payload : un objet JSON de claims, par exemple de qui parle le token, qui l'a émis, qui peut l'utiliser et jusqu'à quand.
Signature : calculée sur <code>base64url(header) + "." + base64url(payload)</code> avec l'algorithme de l'en-tête. Pour HS256, c'est un HMAC-SHA-256 avec le secret partagé.
Base64URL (RFC 7515) utilise <code>-</code> et <code>_</code> à la place de <code>+</code> et <code>/</code> et supprime le remplissage <code>=</code>, si bien qu'un JWT peut figurer dans une URL ou un en-tête tel quel.
Changez un caractère de l'en-tête ou du payload et la signature ne correspond plus : c'est la seule protection qu'offre le format.
Les claims à lire en premier

Sept claims enregistrés (RFC 7519) couvrent la plupart des séances de débogage. Tous sont facultatifs dans la spécification, donc une API peut en exiger plus que la norme.

iss : l'émetteur, en général une URL. sub : le sujet, en général un identifiant d'utilisateur. aud : l'audience, une chaîne ou un tableau.
exp : l'expiration, nbf : pas avant, iat : émis à. Les trois sont des NumericDate : des secondes depuis le 1er janvier 1970 UTC.
jti : un identifiant unique de token, utile quand un serveur tient une liste de refus.
Exemple : iat 1790000000 vaut 2026-09-21T14:13:20Z, et exp 1790003600 une heure plus tard, 15:13:20Z.
Les claims personnalisés comme scope, roles ou tenant dépendent du fournisseur. La spécification ne les définit pas.
Familles d'algorithmes : ce qui signe et ce qui vérifie

La valeur d'alg décide qui peut émettre un token et qui peut seulement en contrôler un.

HS256, HS384, HS512 : un seul secret partagé signe et vérifie, donc tout vérificateur peut aussi falsifier des tokens.
RS256/384/512 et PS256/384/512 (RSA), ES256/384/512 (ECDSA), EdDSA (Ed25519) : une clé privée signe, une clé publique vérifie. Les clés publiques sont ce qu'un fournisseur d'identité publie sous forme de JWKS.
L'encodeur les gère toutes, plus none, qui produit un token terminé par un point, sans aucune signature.
EdDSA signifie ici Ed25519 uniquement, ce qui correspond au périmètre documenté de l'outil.
Choisissez un algorithme asymétrique quand plusieurs services doivent vérifier des tokens qu'un seul service a le droit d'émettre.

Décoder et encoder dans les outils : le pas-à-pas

Inspecter un token avec jwt-decode

Le décodeur JWT n'a pas de bouton : le décodage s'exécute pendant que vous collez ou modifiez, après une courte pause. L'éditeur démarre vide ; « Charger un exemple » ou le choix d'un algorithme charge un token de démonstration.

1

Collez le token compact

Uniquement les trois segments, sans le préfixe Bearer . Les espaces au début et à la fin sont ignorés.

2

Lisez l'en-tête et le payload

Les deux apparaissent en JSON formaté dans leur propre panneau, à côté de la signature brute. Vérifiez d'abord alg, kid, exp, aud et iss.

3

Contrôlez la signature si besoin

Collez le secret HMAC, ou une clé publique en PEM ou JWK pour les algorithmes asymétriques. Le résultat est « Signature vérifiée » ou « Signature invalide », et il ne couvre que la signature.

4

Lisez l'erreur, s'il y en a une

Le décodeur signale un mauvais nombre de parties, un segment vide, une signature manquante (permise seulement pour alg=none) ou un segment qui n'est pas du JSON en Base64URL.

Fabriquer un token de test avec jwt-encode

L'encodeur JWT signe pendant que vous tapez. Le token apparaît dès que l'en-tête, le payload et la clé sont valides.

1

Choisissez l'algorithme

Utilisez la barre d'outils ou modifiez alg dans le JSON de l'en-tête. Un alg absent ou non pris en charge est signalé comme un en-tête invalide.

2

Écrivez les claims

Un objet JSON. iat est écrasé par l'heure actuelle à chaque encodage : impossible de figer un ancien iat.

3

Fixez une expiration si besoin

Le menu Expiration (15 minutes, 1 heure, 24 heures) écrase tout exp présent dans le JSON. « Aucune » garde votre payload tel quel.

4

Fournissez la clé

Un secret pour HMAC, ou une clé privée PEM (PKCS#8) ou JWK pour RSA, ECDSA et EdDSA. Un secret plus court que la longueur recommandée affiche un avertissement avec sa taille en bits.

5

Copiez le token et contrôlez-le

Collez-le dans le décodeur pour voir ce que vous avez produit, puis dans jwt-verify pour tester une vraie politique de vérification.

Ce que les outils ne font pas

Quelques limites à connaître avant de s'appuyer dessus pour un usage précis.

Aucune validation de exp, nbf, aud ou iss dans le décodeur ni l'encodeur : c'est le rôle de jwt-verify
Aucune conversion des horodatages en dates : le décodeur affiche les secondes brutes
Aucune récupération de JWKS à distance, nulle part : les clés se collent
Aucun token chiffré (JWE) : seulement des tokens signés à trois parties
EdDSA se limite à Ed25519
Un token signé ici est une fixture, pas une authentification de production

Les mêmes opérations dans votre propre code

Node : décoder sans vérifier

Le décodage n'exige aucune bibliothèque : découpez sur les points et lisez chaque segment en Base64URL. C'est ce que fait le décodeur, avec la même limite : rien n'est contrôlé.

Exemple de base

// Decode WITHOUT verifying: read the claims, trust nothing. function decodeJwt(token) { const [h, p, s] = token.split('.') if (!h || !p || !s) throw new Error('Format attendu : header.payload.signature') const json = (part) => JSON.parse(Buffer.from(part, 'base64url').toString('utf8')) return { header: json(h), payload: json(p) } } const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzQyIiwic2NvcGUiOiJvcmRlcnM6cmVhZCIsImlzcyI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Im9yZGVycy1hcGkiLCJpYXQiOjE3OTAwMDAwMDAsImV4cCI6MTc5MDAwMzYwMH0.S7icJbfp1NQ88Pkyf9HYZ6tl-jkLgOCOzxFDSCKFLvE' const { header, payload } = decodeJwt(token) console.log(header.alg) // HS256 console.log(new Date(payload.exp * 1000).toISOString()) // 2026-09-21T15:13:20.000Z // Collez ce token dans jwt-decode ; avec le secret "demo-secret-for-docs-only-0123456789abcdef", il affiche « Signature vérifiée »
Signer avec jose

La bibliothèque jose signe un JWT compact et renseigne les claims enregistrés pour vous. Contrairement à l'encodeur d'ici, setIssuedAt() utilise la vraie horloge, comme il se doit en production.

Exemple de base

import { SignJWT } from 'jose' // HS256: key of at least 32 bytes (256 bits), read from the environment const secret = new TextEncoder().encode(process.env.JWT_SECRET) const token = await new SignJWT({ scope: 'orders:read' }) .setProtectedHeader({ alg: 'HS256', typ: 'JWT' }) .setSubject('user_42') .setIssuer('https://auth.example.com') .setAudience('orders-api') .setIssuedAt() .setExpirationTime('1h') .sign(secret)
Vérifier avec l'algorithme imposé

La vérification est l'endroit où se fonde la confiance : imposez l'algorithme, l'émetteur et l'audience, et autorisez une petite tolérance d'horloge.

Exemple de base

import { jwtVerify } from 'jose' try { const { payload } = await jwtVerify(token, secret, { algorithms: ['HS256'], // imposez l'algorithme accepté : ne le lisez jamais dans l'en-tête du token issuer: 'https://auth.example.com', audience: 'orders-api', clockTolerance: 60, // secondes de tolérance pour le décalage d'horloge entre l'émetteur et l'API }) console.log(payload.sub) } catch (err) { // ERR_JWT_EXPIRED, ERR_JWS_SIGNATURE_VERIFICATION_FAILED, ERR_JWT_CLAIM_VALIDATION_FAILED… console.error(err.code) }
FastMinify jwt-decode et jwt-encode

Rien à installer, rien d'envoyé : le décodeur et l'encodeur couvrent la lecture des claims, la fabrication de fixtures et le contrôle d'une signature dont vous détenez la clé. Les compromis : pas de validation des claims, pas de conversion d'horodatages, pas de JWE, EdDSA limité à Ed25519. Pour une vraie décision de confiance, utilisez une bibliothèque de vérification côté serveur, ou collez un JWKS dans jwt-verify pour tester d'abord votre politique.

Conclusion

Un JWT est une enveloppe signée, pas scellée : son payload est lisible par tous, et seule la signature indique qu'il n'a pas été modifié. Le décodeur JWT rend les claims visibles en quelques secondes, ce qui suffit à l'essentiel d'un 401 ou d'un 403, et l'encodeur JWT fabrique un token pour reproduire un cas. Ni l'un ni l'autre n'établit la confiance. Cela demande les clés de l'émetteur, un algorithme imposé et des contrôles sur aud, iss et exp, ce que font jwt-verify et votre propre code serveur. Gardez les secrets de test hors de la production, tirez les secrets HMAC au hasard, et refusez alg=none. Le hub des outils sécurité rassemble les outils voisins pour les clés, les certificats et les secrets.

Inspectez ou fabriquez un token dans votre navigateur

Décodez pour déboguer, vérifiez pour faire confiance : un payload lisible ne prouve rien
Lisez exp, nbf et iat comme des secondes depuis 1970 et convertissez-les vous-même
Imposez l'algorithme côté serveur et refusez alg=none
Tirez les secrets HMAC au hasard, au moins aussi longs que la sortie du hash
Ne collez jamais un token de production actif là où d'autres peuvent le voir, et traitez chaque token comme un identifiant d'accès
Partager cet article
Partager cet article: