Comprendre la structure d’un JWT
Un JWT signé au format compact JWS suit généralement cette structure :
en-tête.payload.signature
Chaque segment a un rôle précis :
- En-tête (header) : indique notamment le type de jeton et l’algorithme utilisé, par exemple
JWTetHS256. - Payload : contient des claims, c’est-à-dire des informations associées au jeton.
- Signature : sert à vérifier l’intégrité et l’authenticité du contenu selon le mécanisme utilisé.
Les deux premiers segments sont encodés en Base64URL. Ils peuvent donc être décodés sans disposer de la clé de signature. En revanche, décoder un JWT ne signifie pas le valider.
Décoder un JWT en JavaScript
Dans un navigateur, il faut convertir le Base64URL en Base64, rétablir le remplissage éventuel, puis interpréter les octets comme du JSON UTF-8.
function decodeBase64UrlJson(value) {
const base64 = value
.replace(/-/g, "+")
.replace(/_/g, "/");
const padded = base64 + "=".repeat((4 - (base64.length % 4)) % 4);
const binary = atob(padded);
const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
const json = new TextDecoder("utf-8").decode(bytes);
return JSON.parse(json);
}
function decodeJwt(token) {
const parts = token.split(".");
if (parts.length !== 3) {
throw new Error("Le jeton ne contient pas trois segments.");
}
return {
header: decodeBase64UrlJson(parts[0]),
payload: decodeBase64UrlJson(parts[1]),
signature: parts[2]
};
}
const token = "VOTRE_JWT_ICI";
const decoded = decodeJwt(token);
console.log("En-tête :", decoded.header);
console.log("Payload :", decoded.payload);
Comment fonctionne ce code ?
split(".")sépare les trois segments du JWT.- Les caractères Base64URL
-et_sont convertis en caractères Base64 classiques. - Le padding manquant, représenté par
=, est ajouté. - Le contenu est décodé en octets, puis converti en texte UTF-8.
- Le texte est enfin analysé comme du JSON.
Décoder un JWT en Python
En Python, le module standard base64 permet de décoder les segments Base64URL.
import base64
import json
def decode_base64url_json(value):
padding = "=" * (-len(value) % 4)
decoded = base64.urlsafe_b64decode(value + padding)
return json.loads(decoded.decode("utf-8"))
def decode_jwt(token):
parts = token.split(".")
if len(parts) != 3:
raise ValueError("Le jeton ne contient pas trois segments.")
return {
"header": decode_base64url_json(parts[0]),
"payload": decode_base64url_json(parts[1]),
"signature": parts[2],
}
token = "VOTRE_JWT_ICI"
decoded = decode_jwt(token)
print("En-tête :", decoded["header"])
print("Payload :", decoded["payload"])
À quoi ressemblent l’en-tête et le payload ?
Après décodage, l’en-tête peut ressembler à ceci :
{
"alg": "HS256",
"typ": "JWT"
}
Le payload peut contenir des claims comme :
{
"sub": "1234567890",
"name": "Jane Doe",
"iss": "https://exemple.test",
"aud": "mon-api",
"iat": 1710000000,
"exp": 1710003600
}
iss identifie généralement l’émetteur, sub le sujet, aud l’audience, iat la date d’émission et exp la date d’expiration. Ces claims ne sont pas obligatoires dans tous les jetons et leur interprétation dépend de l’application.
Décodage et validation : deux opérations différentes
Le décodage permet uniquement de lire le contenu présenté par le jeton. Il ne permet pas de confirmer que :
- le JWT a été émis par un serveur de confiance ;
- son contenu n’a pas été modifié ;
- sa signature est correcte ;
- il n’est pas expiré ou utilisé avant sa date de validité ;
- l’utilisateur dispose réellement de l’autorisation demandée.
Pour accepter un JWT, l’application doit utiliser une bibliothèque adaptée et vérifier notamment la signature, les algorithmes autorisés, l’émetteur (iss), l’audience (aud) et les dates comme exp ou nbf. La liste des algorithmes acceptés doit être définie explicitement.
Décoder un JWT avec un outil en ligne
jwt.io propose un débogueur capable d’afficher l’en-tête et le payload d’un JWT. Cet outil peut aussi aider à vérifier une signature lorsque la clé et les paramètres nécessaires sont disponibles.
Évitez toutefois de copier un jeton réel dans un service tiers sans connaître ses conditions de traitement. Un décodage local, dans le navigateur ou dans un script, limite l’exposition du token.
Précautions à prendre
Un JWT signé n’est pas forcément chiffré
Un JWT signé peut être lu par toute personne qui possède le token. Ne placez donc pas de mot de passe, de clé privée ou d’information confidentielle dans son payload, sauf si un mécanisme de chiffrement approprié est utilisé.
Le cas d’un JWE chiffré
Un jeton JWE compact chiffré comporte généralement cinq segments :
protected-header.encrypted-key.iv.ciphertext.authentication-tag
Son en-tête protégé peut être décodé, mais son contenu chiffré ne peut pas être lu par un simple décodage Base64URL. Une clé et une procédure de déchiffrement adaptées sont nécessaires.
La méthode en résumé
- Récupérez le JWT.
- Séparez-le avec le caractère
.. - Décodez le premier segment en Base64URL puis en JSON pour lire l’en-tête.
- Décodez le deuxième segment de la même façon pour lire le payload.
- Considérez le résultat comme une information lisible, pas comme une preuve de validité.
- Effectuez séparément la vérification cryptographique et les contrôles métier.