En une phrase
Un JSON Web Token (JWT) est une manière compacte et compatible avec les URL de représenter des affirmations (« claims ») à transférer entre deux parties, généralement utilisé pour l'authentification et l'autorisation d'une manière qui peut être vérifiée et jugée digne de confiance.
Le problème que ça résout
Dans les temps anciens — disons, le début des années 2000 — si vous vous connectiez à un site web, le serveur créait une « session » pour vous. C'était comme un petit fichier sur le serveur qui disait : « L'utilisateur 123 est connecté et a mis un poulet en caoutchouc dans son panier. » Le serveur donnait à votre navigateur un minuscule cookie avec un ID de session, comme un ticket de vestiaire. À chaque requête suivante, votre navigateur présentait le ticket, le serveur le recherchait, trouvait votre fichier et se souvenait de qui vous étiez.
Ça fonctionnait bien pour un unique serveur monolithique. Mais ensuite, le web a explosé. On a eu les microservices, les applications monopages (SPA), et les applis mobiles, tous communiquant avec le même backend. Maintenant, votre requête de connexion peut aller au Serveur A, mais votre requête suivante pour récupérer votre profil pourrait aller au Serveur B. Comment le Serveur B est-il au courant du fichier de session sur le Serveur A ?
On pourrait forcer un utilisateur à toujours parler au même serveur (les « sticky sessions »), mais c'est un goulot d'étranglement. On pourrait créer une base de données de sessions centralisée (comme Redis) que tous les serveurs partagent, mais c'est une autre pièce d'infrastructure à gérer et un autre point de défaillance unique.
Le problème fondamental est le statefulness (la gestion d'état). Le serveur doit se souvenir de vous.
Les JWT (prononcés « jots ») ont renversé cette idée. Et si l'utilisateur pouvait transporter sa propre preuve d'identité, comme un passeport ? Le token lui-même contiendrait toutes les informations dont le serveur a besoin : qui est l'utilisateur, ce qu'il est autorisé à faire, et quand son accès expire. Le serveur n'a rien à retenir entre les requêtes. C'est l'authentification stateless (sans état), et c'est la clé pour construire des systèmes distribués et scalables. Le serveur a juste besoin de vérifier si le passeport (le JWT) est valide et n'a pas été falsifié.
Comment ça marche sous le capot
Un JWT n'est pas un blob de charabia indéchiffrable. C'est une chaîne de caractères très spécifique et structurée, composée de trois parties séparées par des points (.).
xxxxx.yyyyy.zzzzz
Décortiquons chaque partie.
Le Header (L'étiquette de « Type »)
La première partie est le header. C'est un simple objet JSON qui contient des métadonnées sur le token lui-même, principalement l'algorithme de signature utilisé et le type du token.
{
"alg": "HS256",
"typ": "JWT"
}
alg: L'algorithme de signature.HS256signifie que ce token est signé avec HMAC-SHA256, un algorithme symétrique (on y revient dans un instant). D'autres options courantes incluentRS256(utilisant une paire de clés publique/privée RSA).typ: Le type de token. Pour les JWT, c'est simplement « JWT ».
Ce JSON est ensuite encodé en Base64Url pour produire la première partie du token. Le Base64 est un schéma d'encodage, pas du chiffrement. Il transforme simplement des données binaires en une chaîne de texte qui peut être transmise en toute sécurité sur le web. Voyez ça comme écrire « CECI EST UNE CARTE POSTALE » au dos d'une carte postale — quiconque l'intercepte peut la lire.
Le Payload (Le département des « Claims »)
La deuxième partie est le payload. C'est là que ça devient intéressant. C'est un autre objet JSON qui contient les « claims » (des affirmations), qui sont des déclarations sur l'utilisateur (le « subject ») et d'autres données utiles.
{
"sub": "10987-23456-98765",
"name": "Grace Hopper",
"admin": true,
"iat": 1516239022,
"exp": 1516242622
}
Les claims se déclinent en trois saveurs :
- Claims enregistrés (Registered Claims) : C'est un ensemble de claims prédéfinis et recommandés pour assurer l'interopérabilité. Ils ne sont pas obligatoires, mais ils sont super utiles.
| Claim | Nom | Description |
|---|---|---|
iss |
Émetteur (Issuer) | Qui a émis le token (ex: https://api.monsupersite.com). |
sub |
Sujet (Subject) | L'utilisateur ou l'entité que le token concerne (ex: un ID utilisateur). |
aud |
Audience | À qui le token est destiné (ex: https://api.monsupersite.com). |
exp |
Date d'expiration | Quand le token expire. Un timestamp Unix numérique (secondes depuis l'epoch). |
iat |
Date d'émission | Quand le token a été émis. Également un timestamp Unix. |
- Claims publics (Public Claims) : Ce sont des claims personnalisés que vous créez, mais pour éviter les conflits de noms, ils doivent être définis dans le registre IANA des claims de JSON Web Token ou être une URI qui contient un espace de noms résistant aux collisions.
- Claims privés (Private Claims) : Ce sont les claims personnalisés les plus courants, créés pour partager des informations entre des parties qui se sont mises d'accord sur leur utilisation (comme
admin: truedans notre exemple). C'est ici que vous mettez vos données spécifiques à votre application.
Tout comme le header, l'intégralité du JSON du payload est encodée en Base64Url pour former la deuxième partie du JWT. Encore une fois, ce n'est pas chiffré. Ne mettez jamais d'informations sensibles comme des mots de passe dans le payload.
La Signature (Le Sceau Inviolable)
C'est la partie qui assure la sécurité. La signature est utilisée pour vérifier que l'émetteur du JWT est bien celui qu'il prétend être et pour s'assurer que le message n'a pas été modifié en cours de route.
Elle est créée en prenant le header encodé, le payload encodé, une clé secrète (un secret), et en les passant dans l'algorithme spécifié dans le header. Pour notre exemple HS256, le processus ressemble à ceci :
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
votre-secret-de-256-bits
)
Le clou du spectacle : un secret est utilisé, que seul le serveur connaît. Quand le serveur reçoit un JWT, il refait exactement le même calcul avec le header et le payload qu'il a reçus. Si la signature qu'il génère correspond à la signature du token, le serveur sait deux choses :
- Authenticité : Le token a été créé par quelqu'un qui connaît la clé secrète (c'est-à-dire, le serveur lui-même).
- Intégrité : Le header et le payload n'ont pas été altérés. Si un attaquant changeait
"admin": falseen"admin": true"dans le payload, la signature ne correspondrait plus.
Cette signature est le sceau holographique inviolable de notre passeport.
Histoires vécues
Le Labyrinthe des Microservices
Une entreprise d'e-commerce en pleine croissance, « ScaleFast », a décidé de diviser son énorme backend monolithique en une flotte de microservices : un pour les utilisateurs, un pour les commandes, un pour l'inventaire, etc. L'ancien système utilisait une session côté serveur. Mais dans ce nouveau monde, comment le OrderService sait-il qu'une requête vient vraiment d'un utilisateur connecté, sans avoir à appeler le UserService à chaque requête ? Ce serait lent et irait à l'encontre de l'objectif de découplage.
La solution fut le JWT. Quand un utilisateur se connecte, le nouveau AuthService émet un JWT contenant le userId et ses roles. Le navigateur de l'utilisateur inclut alors ce JWT dans le header Authorization de chaque requête vers les autres microservices. Le OrderService et l'InventoryService n'ont pas besoin de parler à l'AuthService ; ils ont juste besoin de connaître la clé secrète partagée. Ils peuvent vérifier indépendamment la signature du JWT, faire confiance au userId à l'intérieur, et traiter la requête.
Leçon : Les JWT sont la lingua franca de l'authentification des microservices, permettant aux services d'être stateless et vérifiables de manière indépendante.
La Saga de l'Application Monopage
Un développeur nommé Alex construisait un tableau de bord React très classe. Le frontend était une Application Monopage (SPA) servie depuis un hébergeur statique, et il communiquait avec une API backend séparée. Alex se battait avec une authentification à l'ancienne basée sur les cookies, et se heurtait à un cauchemar de problèmes de Cross-Origin Resource Sharing (CORS) car le frontend et le backend étaient sur des domaines différents.
L'équipe est passée au JWT. Maintenant, après qu'un utilisateur se connecte avec son nom d'utilisateur et son mot de passe, l'API renvoie un JWT. L'application React d'Alex stocke ce token en mémoire et le joint à chaque appel d'API : Authorization: Bearer <le-jwt>. Le backend de l'API est stateless ; il se contente de vérifier le bearer token sur chaque requête entrante. Fini les maux de tête liés aux cookies et à CORS.
Leçon : Les JWT fournissent une information d'identification propre et portable qui fonctionne à merveille pour découpler les applications frontend modernes des API backend.
Erreurs et pièges courants
- Mettre des données sensibles dans le payload. Arrêtez tout ! Le payload est encodé en Base64Url, ce qui est trivialement réversible. Il n'est pas chiffré. Quiconque met la main sur le token peut lire le payload. Considérez-le comme une carte postale, pas une lettre scellée.
- Oublier de vérifier la signature. À quoi servent les dispositifs de sécurité d'un passeport si l'agent à la frontière ne les vérifie pas ? Se contenter de décoder le payload et de faire confiance à son contenu sans vérifier la signature est une vulnérabilité de sécurité catastrophique. Un attaquant pourrait forger n'importe quel payload.
- Faire aveuglément confiance au header
alg. Une vulnérabilité célèbre du passé impliquait des attaquants créant un token et modifiant le header en{"alg": "none"}. Certaines bibliothèques mal configurées voyaient « none » et « vérifiaient » la signature en... ne faisant rien, acceptant ainsi le token falsifié comme valide. Assurez-vous que votre serveur impose toujours un algorithme spécifique et attendu (par ex.,HS256). - Laisser fuiter votre clé secrète symétrique. Pour les algorithmes HMAC comme
HS256, la clé secrète, ce sont les clés du royaume. Si elle fuite, n'importe qui peut forger des tokens pour n'importe quel utilisateur avec n'importe quelles permissions. Protégez-la comme un mot de passe. - Ne pas définir de claim d'expiration (
exp). Un token qui vit éternellement est un énorme risque. S'il est un jour compromis, un attaquant peut l'utiliser indéfiniment. Définissez toujours une durée d'expiration raisonnablement courte et utilisez un mécanisme derefresh tokenpour les sessions de plus longue durée.
Pourquoi vous devriez vous y intéresser
Vous devriez penser « JWT » chaque fois que vous gérez l'authentification ou l'autorisation dans un environnement distribué.
- Vous construisez une API pour une Application Monopage (SPA) ou un client mobile.
- Vous concevez une architecture de microservices où les services doivent pouvoir se faire confiance les uns les autres.
- Vous avez besoin d'une authentification stateless qui peut scaler horizontalement sans un stockage de session partagé.
- Vous mettez en place des flux d'autorisation à usage unique, comme les liens de réinitialisation de mot de passe ou de vérification d'e-mail, pour lesquels un token autonome et périssable est une solution parfaite.
C'est le standard moderne pour représenter des affirmations de manière sécurisée, et comprendre ses forces — et ses faiblesses — n'est pas négociable pour le développeur d'aujourd'hui.
Pour aller plus loin
- RFC 7519: La spécification officielle pour le JSON Web Token (JWT). La source de vérité.
- jwt.io: Une ressource fantastique avec un débogueur en direct et une liste de bibliothèques pour presque tous les langages.
- OWASP JWT Cheat Sheet: Un guide essentiel sur les meilleures pratiques de sécurité et les pièges de l'utilisation des JWT (les conseils sont indépendants du langage).
- MDN Web Docs: Authorization header: Apprenez-en plus sur le schéma d'authentification
Bearercouramment utilisé pour transmettre les JWT. - Wikipedia: JSON Web Token: Un bon aperçu de haut niveau du concept et de son histoire.