Qu’est-ce que JWT ? Les jetons Web JSON expliqués avec un exemple fonctionnel
Un JWT permet à un serveur de faire confiance à une requête sans rien rechercher. Créez-en un à partir de zéro, essayez de le falsifier et regardez-le échouer, puis découvrez quand les jetons battent les sessions et comment les utiliser en toute sécurité.
- Un JWT est un jeton compact et signé composé de trois parties : en-tête, charge utile et signature.
- La signature prouve qu’un jeton n’a pas été modifié, le serveur peut donc lui faire confiance sans recherche.
- La charge utile est lisible par n’importe qui, alors n’y mettez jamais de secrets.
- Les jetons sont difficiles à révoquer, alors gardez-les de courte durée et vérifiez-les auprès d’une bibliothèque fiable.
Une fois connecté, comment un serveur sait-il que chaque demande ultérieure émane réellement de vous ? Une réponse populaire est un JSON Web Token, ou JWT, généralement prononcé « jot ». Il s’agit d’un petit morceau de données signé que le client envoie à chaque requête, et le serveur peut le vérifier sans toucher à une base de données.
Le moyen le plus rapide de comprendre un JWT est d’en créer un, puis d’essayer de le casser. Nous l’avons fait en utilisant uniquement la bibliothèque standard de Python, sur Python 3.13, et le résultat ci-dessous provient de cette exécution. Ce code est destiné à l’apprentissage. Dans une application réelle, utilisez une bibliothèque bien entretenue, car il est facile de se tromper sur les détails de la vérification.
Qu’est-ce qu’un JWT ?
JWT est un standard ouvert, défini dans la RFC 7519, permettant de transmettre des revendications entre deux parties sous la forme d’une chaîne compacte. Une revendication est simplement une déclaration, telle que « l’ID de cet utilisateur est 42 ». Le token étant signé, le destinataire peut confirmer qui l’a émis et que personne ne l’a modifié.
Pensez à un bracelet de festival. Le personnel à la porte vérifie votre billet une fois et vous donne un bracelet difficile à falsifier. Après cela, chaque stand se contente de regarder le groupe, sans avoir besoin de téléphoner à la billetterie. Un JWT fonctionne à peu près de la même manière pour une API.
Comment fonctionne la connexion JWT
- L’utilisateur envoie un nom d’utilisateur et un mot de passe au point de terminaison de connexion.
- Le serveur les vérifie et crée un jeton signé.
- Le client stocke le jeton.
- Chaque requête ultérieure l’inclut, généralement dans un en-tête :
Authorization: Bearer <token>. - Le serveur vérifie la signature et l’expiration, puis lit les réclamations.
Le principal avantage réside dans l’étape 5. Le serveur n’a pas besoin de rechercher une session, ce qui est pratique lorsque de nombreux services ou serveurs doivent vérifier le même jeton. Si vous débutez avec les API, commencez par qu’est-ce qu’une API.
Les trois parties d’un JWT
Un JWT ressemble à du texte aléatoire, mais il s’agit de trois sections codées en Base64URL séparées par des points. En voici un que nous avons généré :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiI0MiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzkzNTAwMDAwLCJleHAiOjE3OTM1MDA5MDB9
.7YfUDH_T-iDh8bMmUT8mmKYwOstzT8Ty--DTTAmQGWM
Nous avons ajouté des sauts de ligne pour faciliter la lecture. Le décodage des deux premières parties donne du JSON simple :
Header: {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"42","role":"user","iat":1793500000,"exp":1793500900}
| Partie | Contient | Objectif |
|---|---|---|
| En-tête | Type de jeton et algorithme de signature | Dit comment vérifier le jeton |
| Charge utile | Réclamations concernant l’utilisateur ou la session | Les informations réelles |
| Signature | Un hachage des deux premières parties, à l’aide d’une clé | Prouve l’intégrité et l’origine |
Allégations standards
| Réclamation | Nom | Signification |
|---|---|---|
sous |
Sujet | De qui concerne le jeton, généralement un identifiant utilisateur |
est |
Émetteur | Qui a créé le jeton |
aud |
Public | À qui est destiné le jeton |
exp |
Expiration | Lorsque le jeton cesse d’être valide |
ça |
Publié à | Quand il a été créé |
nbf |
Pas avant | Quand il commence à être valide |
jti |
ID JWT | Un identifiant unique pour ce jeton |
Vous pouvez également ajouter des revendications personnalisées, comme role. Les heures sont des horodatages Unix, en secondes. Gardez la charge utile petite, car le jeton se déplace à chaque demande.
Construisez-en un vous-même
La création d’un jeton implique d’encoder les deux parties JSON, puis de les signer avec un secret à l’aide de HMAC-SHA256 :
import base64, hashlib, hmac, json
SECRET = b"demo-secret-do-not-use-in-production"
def b64url(data):
return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
def sign(message):
return b64url(hmac.new(SECRET, message.encode(), hashlib.sha256).digest())
def create_token(payload):
header = {"alg": "HS256", "typ": "JWT"}
parts = [
b64url(json.dumps(header, separators=(",", ":")).encode()),
b64url(json.dumps(payload, separators=(",", ":")).encode()),
]
message = ".".join(parts)
return message + "." + sign(message)
La vérification fonctionne en recalculant la signature et en la comparant avec celle du jeton. Seule une personne possédant le secret peut en produire un correspondant :
def verify_token(token, now):
header, payload, signature = token.split(".")
expected = sign(header + "." + payload)
if not hmac.compare_digest(signature, expected):
raise ValueError("bad signature")
claims = json.loads(b64url_decode(payload))
if claims["exp"] < now:
raise ValueError("token expired")
return claims
Un jeton valide a renvoyé ses réclamations comme prévu. compare_digest est utilisé car il fonctionne en temps constant, ce qui évite les fuites d’informations dues à des différences temporelles.
Essayez de le falsifier
Supposons qu’un attaquant décode la charge utile, modifie "role":"user" en "role":"admin", la code à nouveau et conserve l’ancienne signature. Nous avons essayé ceci, ainsi que deux autres attaques :
| Tentative | Résultat |
|---|---|
| J’ai changé le rôle en administrateur | mauvaise signature |
| Utilisé le jeton 1 seconde après son expiration | jeton expiré |
Définir "alg":"none" et supprimer la signature |
mauvaise signature |
Cette dernière tentative vise une véritable faiblesse historique. Certaines bibliothèques faisaient autrefois confiance au propre en-tête du jeton, de sorte qu’un attaquant pouvait simplement déclarer qu’aucune signature n’était nécessaire. Notre code utilise toujours un algorithme fixe, c’est pourquoi il a été rejeté. Dans une vraie bibliothèque, précisez toujours les algorithmes que vous acceptez.
Signé, non crypté
C’est le point le plus mal compris à propos des JWT. Notre faux token a été rejeté, mais son contenu était toujours parfaitement lisible :
{"sub":"42","role":"admin","iat":1793500000,"exp":1793500900}
Base64URL est un codage, pas un cryptage, et n’importe qui peut l’inverser sans aucune clé. La signature empêche les gens de modifier les données, mais pas de les lire. Ne mettez donc jamais de mots de passe, de numéros de carte ou de données personnelles privées dans une charge utile JWT. Si le contenu doit être masqué, utilisez des jetons cryptés (JWE) ou conservez simplement les données sur le serveur.
HS256 contre RS256
| Aspect | HS256 | RS256 ou ES256 |
|---|---|---|
| Tapez | Symétrique | Asymétrique |
| Clés | Un secret partagé | Une clé privée signe, une clé publique vérifie |
| Qui peut créer des jetons | Quiconque détient le secret | Uniquement le détenteur de la clé privée |
| Idéal pour | Un service ou un petit groupe de confiance | De nombreux services, tiers, fournisseurs d’identité |
Avec la signature asymétrique, d’autres services peuvent vérifier les jetons sans pouvoir créer les leurs, ce qui limite les dégâts en cas de compromission.
JWT vs sessions
Les JWT sont souvent présentés comme un remplacement moderne des sessions. En réalité, chacun a des compromis :
| Aspect | Session serveur | JWT |
|---|---|---|
| Où vit l’État | Sur le serveur | Dans le jeton |
| Recherche sur chaque demande | Habituellement | Pas nécessaire |
| Déconnexion ou révocation | Facile, supprimez la session | Difficile avant expiration |
| Taille par demande | Petite pièce d’identité | Jeton plus grand (le nôtre comptait 161 caractères) |
| À travers de nombreux services | Nécessite un stockage partagé | Chacun peut le vérifier directement |
| Modification des autorisations | S’applique immédiatement | L’ancien jeton reste valable jusqu’à son expiration |
Pour un site Web traditionnel rendu par un serveur, un cookie de session est souvent plus simple et plus sûr. Les JWT ont tendance à avoir plus de sens pour les API consommées par plusieurs services ou pour les clients mobiles.
Conseil : Ne choisissez pas JWT simplement parce que cela semble apatride. De nombreux systèmes réels ajoutent une liste de refus ou une vérification de base de données pour prendre en charge la déconnexion, ce qui ramène la recherche que JWT était censé éviter.
Où stocker les jetons dans un navigateur
| Emplacement | Risque XSS | Risque CSRF | Remarques |
|---|---|---|---|
stockage local |
Élevé, comme les scripts peuvent le lire | Faible | Simple, mais exposé à tout script injecté |
| Cookie HttpOnly | Inférieur, car les scripts ne peuvent pas le lire | A besoin de protection | Utilisez Secure et SameSite |
| Variable en mémoire | Inférieur | Faible | Perdu lors de l’actualisation, il nécessite donc un flux d’actualisation |
De nombreux guides de sécurité privilégient les cookies HttpOnly, Secure, SameSite pour les applications Web. Quel que soit votre choix, utilisez toujours HTTPS. Pour envoyer un jeton depuis JavaScript, consultez notre Tutoriel API JavaScript Fetch.
Actualiser les jetons
Une expiration courte limite les dégâts d’un jeton volé, mais personne ne veut se connecter toutes les 15 minutes. La solution habituelle utilise deux jetons :
- Jeton d’accès : de courte durée, par exemple quelques minutes, et envoyé avec chaque requête API.
- Jeton d’actualisation : plus durable, stocké plus soigneusement et utilisé uniquement pour obtenir de nouveaux jetons d’accès.
Le serveur garde une trace des jetons d’actualisation afin de pouvoir les révoquer, ce qui vous permet de vous déconnecter de manière pratique. Leur rotation à chaque utilisation vous aide également à détecter le vol, car un ancien token volé est rejoué.
Erreurs de sécurité courantes
- Décoder sans vérifier. La lecture d’une charge utile ne la rend pas fiable. Vérifiez toujours la signature.
- Accepter n’importe quel algorithme. Définissez une liste explicite d’algorithmes autorisés.
- Utilisation d’un secret faible. Les secrets courts peuvent être déchiffrés hors ligne. Utilisez une longue valeur aléatoire et conservez-la hors du contrôle de code source.
- Saut d’expiration. Les jetons sans
exppeuvent fonctionner pour toujours s’ils sont volés. - Ne pas vérifier
issetaud. Sinon, un jeton émis pour un service peut être accepté par un autre. - Faire confiance aux revendications obsolètes. Un rôle à l’intérieur d’un jeton peut être obsolète jusqu’à son expiration.
- Jetons de journalisation. Toute personne lisant vos journaux peut les réutiliser.
- Ne pas tester les chemins d’échec. Ajoutez des tests pour les jetons expirés et modifiés, ainsi que pour les jetons valides. Notre guide Tests d’API avec Postman peut vous aider.
Pour conclure
Un JWT est constitué de données signées auxquelles un serveur peut faire confiance sans recherche, ni conteneur secret ni mise à niveau automatique au fil des sessions. Utilisez une expiration courte, vérifiez tout avec une bibliothèque maintenue et gardez les données privées hors de la charge utile. Pour le constater par vous-même, exécutez un petit script comme le nôtre, modifiez un caractère d’un jeton et regardez la vérification échouer.
Questions fréquentes
A quoi sert un JWT ?
Les JWT sont principalement utilisés pour l’authentification et l’autorisation dans les API. Après la connexion, un client envoie le jeton avec chaque demande et le serveur le vérifie pour identifier l’utilisateur.
Un JWT est-il chiffré ?
Généralement non. Un JWT standard est signé et codé afin que tout le monde puisse lire sa charge utile. La signature empêche uniquement les modifications. Les jetons cryptés utilisent un format connexe appelé JWE.
Combien de temps un JWT doit-il durer ?
Les jetons d’accès sont généralement de courte durée, souvent quelques minutes plutôt que quelques jours. Associez-les à un jeton d’actualisation afin que les utilisateurs n’aient pas à se connecter constamment.
Un JWT peut-il être révoqué ?
Pas en soi, car il reste valable jusqu’à son expiration. La révocation nécessite un suivi côté serveur, tel qu’une liste de refus, ce qui supprime une partie des avantages liés à l’état apatride.
JWT est-il meilleur que les sessions ?
Ni l’un ni l’autre n’est toujours mieux. Les sessions sont plus simples à révoquer et conviennent à de nombreux sites Web, tandis que les JWT conviennent aux API et aux services qui doivent vérifier l’identité de manière indépendante.
Continuez à apprendre
Besoin d’aide pour les tests, WordPress ou le référencement ?
Nous aidons les équipes à proposer de meilleurs logiciels et à développer leurs sites. Dites-nous sur quoi vous travaillez et nous vous proposerons une prochaine étape claire.
Plus de guides sur tests, IA et développement moderne
Vous avez apprécié cet article ? Choisissez un sujet et accédez directement à nos nouveaux didacticiels.
Les hallucinations de l'IA expliquées : pourquoi les modèles de langage inventent les choses et comment les réduire
Les hallucinations de l'IA ont expliqué : ce qu'elles sont, pourquoi les modèles de langage les produisent, les types courants, comment les réduire …
Lire l'article →DevOpsVariables d'environnement expliquées : fichiers .env, secrets et configuration correctement effectués
Variables d'environnement expliquées avec des exemples Python que nous avons exécutés : lecture et définition, pourquoi chaque valeur est une chaîne…
Lire l'article →Développement logicielLimitation du débit de l'API expliquée : algorithmes, en-têtes et gestion des erreurs 429
Limitation du débit de l'API expliquée avec une simulation que nous avons exécutée : compartiment de jetons, fenêtre fixe, fenêtre glissante, 429 ré…
Lire l'article →Automatisation des testsSe moquer en Python : unittest.mock, patch et les erreurs qui font mentir les tests
Moquerie en Python avec unittest.mock, testée : Mock et return_value, side_effect, correctifs où un nom est utilisé, spec et autospec, dates moqueus…
Lire l'article →Tests logicielsCouverture du code expliquée : couverture des lignes par rapport aux branches et ce que signifie réellement 100 %
Couverture du code expliquée avec une véritable exécution de cover.py : couverture des lignes, des branches et des conditions, lecture d'un rapport,…
Lire l'article →Bases de données et SQLDELETE vs TRUNCATE vs DROP dans SQL : différences, restauration et quand les utiliser
DELETE vs TRUNCATE vs DROP expliqué avec SQL testé : ce que chacun supprime, restauration, déclencheurs, réinitialisation d'identité, vitesse et en …
Lire l'article →Bases de données et SQLVues SQL expliquées : créez, utilisez et évitez les pièges, avec des exemples
Vues SQL expliquées avec les requêtes que nous avons exécutées : création d'une vue, résultats en direct, masquage des colonnes, performances, vues …
Lire l'article →Développement logicielInterface TypeScript vs Type : différences réelles, testées avec le compilateur
Interface TypeScript vs type, vérifiée avec le vrai compilateur : ce que les deux peuvent faire, ce qu'un seul peut faire, la fusion des déclaration…
Lire l'article →Développement logicielPython *args et **kwargs expliqués : fonctions flexibles avec des exemples clairs
Python *args et **kwargs expliqués avec le code que nous avons exécuté : emballage et déballage, ordre des paramètres, arguments de mot-clé uniqueme…
Lire l'article →Développement logicielFonctions Python Lambda : syntaxe, utilisations réelles et quand ne pas les utiliser
Fonctions Python lambda expliquées avec le code que nous avons exécuté : syntaxe, tri avec clé, carte et filtre, fermetures, piège de liaison tardiv…
Lire l'article →Intelligence artificielleQue sont les agents IA ? Comment ils fonctionnent, avec une simple boucle d'agent que vous pouvez exécuter
Que sont les agents IA ? Un guide simple sur la boucle d'agent, les outils, la mémoire et les garde-fous, avec une petite boucle Python que nous avo…
Lire l'article →DevOpsSurveillance vs observabilité : la vraie différence, avec les journaux, les métriques et les traces
Surveillance et observabilité expliquées : échecs connus et inconnus, journaux, métriques et traces, présentation pas à pas des incidents de paiemen…
Lire l'article →DevOpsVolumes Docker vs montages Bind : conserver les données du conteneur de la bonne manière
Volumes Docker et montages de liaison expliqués : pourquoi les données du conteneur disparaissent, volumes nommés, montages de liaison, tmpfs, exemp…
Lire l'article →Automatisation des testsTDD vs BDD : principales différences, une fonctionnalité conçue dans les deux sens et quand les utiliser
TDD vs BDD expliqué avec une fonctionnalité de remise construite dans les deux sens : refactor rouge-vert avec le code que nous avons exécuté, scéna…
Lire l'article →Tests logicielsTests d'acceptation utilisateur (UAT) : processus, liste de contrôle et exemples réels
Les tests d'acceptation des utilisateurs sont expliqués : qui les exécute, en quoi ils diffèrent du contrôle qualité, un processus en sept étapes, u…
Lire l'article →Bases de données et SQLExplication des valeurs SQL NULL : IS NULL, COALESCE, NULLIF et les pièges à éviter
Les valeurs SQL NULL expliquées avec les requêtes que nous avons exécutées : logique à trois valeurs, IS NULL, COALESCE, NULLIF, comment les agrégat…
Lire l'article →Bases de données et SQLInstruction SQL CASE WHEN : syntaxe, exemples réels et erreurs courantes
SQL CASE WHEN expliqué avec les requêtes que nous avons exécutées : formulaires simples et recherchés, ordre des conditions, pivots avec SUM, astuce…
Lire l'article →Développement logicielQu'est-ce que JWT ? Les jetons Web JSON expliqués avec un exemple fonctionnel
Qu’est-ce que JWT ? JSON Web Tokens expliqué : les trois parties, un jeton construit et falsifié dans le code que nous avons exécuté, JWT vs session…
Lire l'article →Développement logicielBoucle d'événements JavaScript expliquée : pile d'appels, microtâches et minuteries avec des exemples
La boucle d'événements JavaScript expliquée avec le code que nous avons exécuté : pile d'appels, files d'attente de tâches et de microtâches, pourqu…
Lire l'article →Développement logicielGénérateurs Python et rendement expliqués : économisez de la mémoire avec des exemples réels
Les générateurs Python et le rendement expliqués avec le code que nous avons exécuté : comment ils s'arrêtent et reprennent, les économies de mémoir…
Lire l'article →Intelligence artificielleQue sont les intégrations ? Vecteurs et similarité cosinus expliqués simplement
Que sont les intégrations ? Un guide en langage simple sur les vecteurs, la similarité cosinus et la recherche sémantique, avec un petit exemple que…
Lire l'article →DevOpsDéploiement Bleu-Vert vs Canary : différences, compromis et comment choisir
Explication du déploiement bleu-vert ou canari : comment chacun fonctionne, coût, risque et restauration, regroupement d'utilisateurs stable que nou…
Lire l'article →Automatisation des testsTests instables : quelles sont leurs causes et comment les corriger définitivement
Des tests irréguliers expliqués avec des démos que nous avons exécutées : les principales causes, comment en confirmer et en diagnostiquer une, les …
Lire l'article →Tests logicielsTests de charge vs tests de contrainte : différences, métriques et exemples k6
Explication des tests de charge et des tests de stress : ce que chacun prouve, les tests de pointe et de trempage, les métriques qui comptent, pourq…
Lire l'article →Tests logicielsScénario de test et scénario de test : principales différences, exemples et quand les utiliser
Scénario de test et scénario de test expliqués : des définitions claires, un tableau côte à côte, une fonctionnalité de réinitialisation de mot de p…
Lire l'article →Bases de données et SQLOptimisation des requêtes SQL : lire les plans d'exécution et corriger les requêtes lentes, avec des délais
Optimisation des requêtes SQL testée sur un million de lignes : lire les plans d'exécution, ajouter les bons index, corriger les filtres non Sargabl…
Lire l'article →Bases de données et SQLSQL UNION vs UNION ALL : différences, exemples et performances testées
SQL UNION vs UNION ALL expliqué avec les requêtes que nous avons exécutées : des doublons, les règles suivent toutes les deux, un véritable bug de d…
Lire l'article →Développement logicielTutoriel API JavaScript Fetch : GET, POST, gestion des erreurs et délais d'attente
Un didacticiel de l'API JavaScript Fetch testé sur un serveur local : GET et POST, pourquoi 404 ne lance pas, un assistant réutilisable, des chaînes…
Lire l'article →Développement logicielGestion des fichiers Python : lecture, écriture, CSV, JSON et pathlib avec exemples
Gestion des fichiers Python expliquée avec le code que nous avons exécuté : modes ouverts, avec lecture de fichiers volumineux, CSV, JSON, pathlib, …
Lire l'article →Développement logicielClasses et objets Python : didacticiel POO avec des exemples réels
Classes et objets Python expliqués avec le code que nous avons exécuté : __init__, méthodes, attributs de classe par rapport à l'instance, héritage,…
Lire l'article →Intelligence artificielleQu'est-ce qu'un grand modèle de langage ? Comment fonctionnent les LLM, expliqués sans battage médiatique
Qu’est-ce qu’un grand modèle de langage ? Les LLM expliqués en langage simple : jetons, intégrations, attention, formation, fenêtres de température …
Lire l'article →DevOpsCommandes Linux pour les débutants : le guide du terminal essentiel avec des exemples
Commandes Linux pour débutants, regroupées par tâche : navigation, fichiers, affichage des journaux, grep, tuyaux, autorisations, processus et archi…
Lire l'article →Automatisation des testsSelenium vs Playwright : principales différences, code comparé et lequel choisir
Comparatif Selenium vs Playwright : architecture, attente, support du navigateur et du langage, débogage, même test dans les deux outils, conseils d…
Lire l'article →Tests logicielsPartitionnement d'équivalence : technique de conception de tests expliquée avec des exemples concrets
Le partitionnement d'équivalence expliqué : comment trouver des partitions valides et invalides, des exemples concrets d'âges, de mots de passe et d…
Lire l'article →Tests logicielsGravité vs priorité dans les tests logiciels : différences, matrice et exemples réels
Explication de la gravité et de la priorité dans les tests logiciels : des définitions claires, une matrice à quatre voies avec des exemples, des éc…
Lire l'article →Bases de données et SQLTutoriel sur les sous-requêtes SQL : types, sous-requêtes corrélées et EXISTE avec des exemples
Un didacticiel sur les sous-requêtes SQL avec les requêtes que nous avons exécutées : les sous-requêtes scalaires, IN, FROM et SELECT, les sous-requ…
Lire l'article →Bases de données et SQLTransactions SQL et ACID expliquées : COMMIT, ROLLBACK et niveaux d'isolement
Transactions SQL et ACID expliquées avec un virement bancaire que nous avons effectué : COMMIT, ROLLBACK, points de sauvegarde, verrous, niveaux d'i…
Lire l'article →Développement logicielGit merge vs rebase : différences, exemples et quand utiliser chacun
Git merge vs rebase expliqué avec de vraies sorties de log, un tableau comparatif, la règle d'or du rebase et un flux de travail sûr pour les équipes.
Lire l'article →Développement logicielList comprehension Python : syntaxe, exemples et cas à éviter
La list comprehension Python expliquée : syntaxe, filtres, if-else, boucles imbriquées, temps mesurés et cas où une boucle for classique est préféra…
Lire l'article →Bases de données et SQLJointures SQL expliquées avec exemples (Inner, Left, Right, Full)
Comprenez les jointures SQL pas à pas avec des tables et requêtes d'exemple : INNER, LEFT, RIGHT, FULL, CROSS et SELF, plus erreurs courantes et con…
Lire l'article →