Quand je décode un JWT, je ne lis pas les claims au hasard. J'utilise une séquence stable pour répondre rapidement à quatre questions : qui l'a émis, pour qui il est prévu, s'il est actif dans le temps et quelles données d'autorisation l'application peut interpréter.
Je commence généralement avec JWT Decoder, puis je passe des registered claims aux claims spécifiques au protocole ou au produit.
Mon ordre de lecture
Pour :
{
"iss": "https://auth.example.com/",
"sub": "user_123",
"aud": "api://orders",
"scope": "orders:read orders:write",
"iat": 1789200000,
"exp": 1789203600
}
je regarde d'abord :
iss— qui affirme avoir émis le token ?aud— pour quelle API ou quel recipient ?expetnbf— le token est-il dans sa fenêtre temporelle ?iat— quand affirme-t-il avoir été émis ?sub— quel sujet représente-t-il ?scope,roles,groups— quelles données d'autorisation ?jti,azp,auth_time,acr,amr— quel contexte supplémentaire ?
iss : issuer
{ "iss": "https://login.example.com/" }
Je compare ce claim avec l'issuer configuré par l'API. Avant signature verification, ce n'est encore qu'une valeur non fiable.
RFC 8725 ajoute une règle essentielle : les clés utilisées pour la verification doivent appartenir à l'issuer que l'application a décidé de faire confiance.
Pour diagnostiquer ce point, j'utilise JWT Debugger et la guide issuer validation.
aud : audience
aud peut être un string :
{ "aud": "api://orders" }
ou un array :
{ "aud": ["api://orders", "api://reporting"] }
Un token correctement signé peut encore être destiné à une autre API. C'est pourquoi audience reste une vérification indépendante.
La guide audience mismatch couvre les erreurs environment et token type.
exp : expiration
exp est une NumericDate en secondes. J'utilise JWT Expiry Checker pour la convertir rapidement.
Un exp futur ne prouve pas que le token est globalement valide. Cela signifie uniquement qu'une condition temporelle n'a pas encore échoué.
nbf : not before
Si nbf est dans le futur, le token n'est pas encore actif même s'il n'est pas expiré.
Près de la limite, je compare les clocks de l'issuer et du verifier et une éventuelle petite tolerance.
iat : issued at
Je l'utilise comme contexte :
- correspond-il au login que je débogue ?
- le token est-il anormalement ancien ?
- la durée
iat→expest-elle plausible ? iatest-il étrangement futur ?
Je ne crée pas de règle universelle de maximum age à partir de iat sans policy applicative.
sub : subject
sub peut représenter un utilisateur, un service ou un autre principal. Je ne l'interprète pas hors du contexte de l'issuer.
Deux issuers différents peuvent réutiliser le même sub sans désigner la même identité. Souvent, iss + sub est une meilleure clé logique.
jti : identifiant du JWT
jti peut identifier une instance de token, mais sa présence ne fournit pas automatiquement replay protection ou revocation. Ces comportements nécessitent policy et souvent state côté serveur.
scope, roles, groups
{
"scope": "profile orders:read",
"roles": ["support", "billing"],
"groups": ["employees"]
}
Ces données sont très utiles au debugging mais n'ont pas de sémantique universelle. Chaque provider décide comment exprimer permissions et groupes.
Après une authentication réussie suivie d'un 403, c'est la couche que j'examine.
Claims OAuth/OIDC supplémentaires
Je peux aussi regarder :
azp— authorized party ;auth_time— moment de l'authentication ;acr— authentication context class ;amr— méthodes d'authentication.
Je ne les utilise pour une décision que si le protocole/provider définit clairement leur sens.
Ma règle de confiance
- Decode : que dit le token ?
- Verify : la signature correspond-elle à une key fiable ?
- Validate : issuer, audience, temps et permissions satisfont-ils la policy ?
Je ne saute jamais de l'étape 1 à « utilisateur authentifié ».
Ma checklist de claims
- Décoder JWT sans lui faire confiance.
- Comparer
issau configured issuer. - Comparer
audà l'API actuelle. - Lire
exp,nbf,iatcomme une timeline. - Interpréter
subdans le contexte de l'issuer. - Évaluer scope/roles/groups après authentication.
- Vérifier signature avec une key source liée à l'issuer.
- Vérifier les claims spécifiques avec la documentation du provider.
Je me concentre d'abord sur trust, recipient, temps et authorization, pas sur chaque clé du payload avec la même importance.