Skip to content

🔬 Module 2 — Anatomie d'un JWT

Bonne lecture et bon apprentissage ! Junior TSAFACK – 12/09/2026 ⏱️ Temps de lecture estimé : 6 minutes


Un JWT ressemble toujours à ceci : trois blocs de texte séparés par des points.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTQyIiwibmFtZSI6Ikp1bmlvciBUU0FGQUNLIiwicm9sZSI6ImZvcm1hdGV1ciIsImlhdCI6MTc1NzY3ODQwMH0.nnywn_YNGOtGTbuj5A_qFUc_VtzUPUXJi5oqDB-Ne9g
HEADER PAYLOAD SIGNATURE

🧩 HEADER.PAYLOAD.SIGNATURE — retenez cet ordre, tout le reste du cours en découle.

Générons un vrai token pour l’observer

Section titled “Générons un vrai token pour l’observer”
import base64
import json
import jwt
SECRET = "un-secret-de-demonstration-ne-jamais-utiliser-en-production"
payload = {
"sub": "user-42",
"name": "Junior TSAFACK",
"role": "formateur",
"iat": 1757678400, # 2026-09-12T12:00:00Z (fixe pour un exemple reproductible)
}
token = jwt.encode(payload, SECRET, algorithm="HS256")
print("Token complet :")
print(token)

Sortie réellement obtenue :

Token complet :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTQyIiwibmFtZSI6Ikp1bmlvciBUU0FGQUNLIiwicm9sZSI6ImZvcm1hdGV1ciIsImlhdCI6MTc1NzY3ODQwMH0.nnywn_YNGOtGTbuj5A_qFUc_VtzUPUXJi5oqDB-Ne9g
header_b64, payload_b64, signature_b64 = token.split(".")
def decode_part(b64_part: str) -> str:
padded = b64_part + "=" * (-len(b64_part) % 4)
return base64.urlsafe_b64decode(padded).decode()
print(decode_part(header_b64))
{"alg":"HS256","typ":"JWT"}

C’est juste du Base64URL (une variante de Base64 sans caractères qui posent problème dans une URL) — pas du chiffrement. alg annonce l’algorithme de signature utilisé (ici HS256, voir Module 4), typ confirme qu’il s’agit d’un JWT.

2️⃣ Le PAYLOAD : les données (« claims »)

Section titled “2️⃣ Le PAYLOAD : les données (« claims »)”
print(json.dumps(json.loads(decode_part(payload_b64)), indent=2, ensure_ascii=False))
{
"sub": "user-42",
"name": "Junior TSAFACK",
"role": "formateur",
"iat": 1757678400
}

⚠️ N’importe qui peut décoder cette partie — nous venons de le faire avec trois lignes de Python, sans connaître le moindre secret. C’est pour ça que le Module 1 insistait : un JWT n’est jamais un coffre-fort, c’est une carte d’identité scellée.

Le payload est fait de claims (revendications). Certaines sont standardisées par la RFC 7519 et ont un sens particulier :

Claim Signification Exemple
sub (subject) L’identifiant de l’utilisateur/l’entité concernée "user-42"
iat (issued at) Horodatage Unix de la création du token 1757678400
exp (expiration) Horodatage Unix après lequel le token est invalide voir Module 4
iss (issuer) Qui a émis le token "https://auth.monentreprise.com"
aud (audience) Pour quel service ce token est destiné "api-facturation"

Rien n’empêche d’ajouter des claims « maison » (comme role ci-dessus) — c’est même l’usage le plus courant pour transporter des permissions.

3️⃣ La SIGNATURE : la seule partie qu’on ne peut pas lire

Section titled “3️⃣ La SIGNATURE : la seule partie qu’on ne peut pas lire”
print(signature_b64)
nnywn_YNGOtGTbuj5A_qFUc_VtzUPUXJi5oqDB-Ne9g

Contrairement aux deux premières parties, la signature n’est pas un encodage réversible de données : c’est le résultat d’une fonction cryptographique (HMAC-SHA256 pour HS256) appliquée à header_b64 + "." + payload_b64, avec un secret que seul le serveur connaît. On ne peut pas la « décoder » — on peut seulement la recalculer et comparer, ce qui est exactement ce que fait la vérification étudiée au Module 4.

  • Un JWT = header.payload.signature, chacun encodé en Base64URL.
  • Header + Payload sont lisibles par tout le monde, signature ou pas.
  • Seule la Signature garantit l’intégrité (« ça n’a pas été modifié ») — jamais la confidentialité.

👉 Module 3 : Le flux d’authentification complet