Vérifier si un token JWT a expiré (claim exp expliqué)

Par • 31 Octobre, 2026 • Sécurité • 12 minutes de lecture

Vérifiez si un JWT a expiré : lisez la claim exp dans votre fuseau horaire et évitez les pièges des millisecondes, du leeway et du base64url. Gratuit.

Un token JWT a expiré dès que l’heure actuelle est égale ou postérieure à sa claim exp. exp est un nombre de secondes écoulées depuis le 1er janvier 1970 UTC : 1793372400 correspond au 30 octobre 2026 à 15:00:00 UTC, soit 16 h à Paris. Pour vérifier un token, on décode sa partie centrale, on lit exp et on compare avec l’horloge. Notre décodeur JWT gratuit le fait pour vous. Collez le token : il affiche Expiré ou Non expiré, avec la date exacte dans votre fuseau horaire et en UTC.

Il est gratuit, sans compte, et fonctionne entièrement dans votre navigateur. Lors de notre test du 31 octobre 2026, la page n’a envoyé aucune requête contenant le token. Les visiteurs ont droit à 5 utilisations d’outils par jour, et un compte My Botsy gratuit (100 % gratuit, sans spam) supprime cette limite. Tous les résultats cités sont réels. Ceux du décodeur viennent de tests sur mybotsy.com le 31 octobre 2026, ceux des bibliothèques de PyJWT 2.15.1, jsonwebtoken 9.0.3 et jose 6.2.14, exécutées le même jour.

Ce que signifie la claim exp

La RFC 7519, qui définit les JWT, prévoit trois claims de temps. Toutes trois sont facultatives, et toutes trois sont des NumericDate : des secondes, pas des millisecondes.

  • exp (expiration time) : à partir de cet instant inclus, le token ne doit plus être accepté.
  • nbf (not before) : avant cet instant, le token ne doit pas non plus être accepté.
  • iat (issued at) : le moment où il a été émis. Il n’invalide rien à lui seul, mais il permet de calculer l’âge du token.

Pour exp et nbf, la RFC autorise une petite marge, « généralement pas plus de quelques minutes », pour compenser le décalage entre les horloges. C’est pourquoi deux systèmes peuvent être en désaccord sur un token expiré depuis quelques secondes.

Vérifier l’expiration d’un token JWT, étape par étape

  1. Copiez le token. C’est la longue chaîne avec deux points qui suit Authorization: Bearer dans les en-têtes d’une requête, ou qui est stockée dans un cookie ou le localStorage.
  2. Collez-le dans le décodeur JWT. Inutile de le nettoyer avant : l’outil retire Authorization:, Bearer, les guillemets, les espaces et les retours à la ligne, et vous le signale.
  3. Lisez la ligne Statut. Elle indique Expiré, Non expiré, Pas encore valide (quand nbf est dans le futur), Sans expiration (pas de exp) ou Expiration illisible : exp n'est pas un nombre valide (quand exp est présent mais n’est pas un nombre).
  4. Regardez la ligne Expire le (exp). Elle donne la date dans votre fuseau, le même instant en UTC, une durée relative (« hier », « dans 2 mois ») et le nombre brut.
  5. Vérifiez la Durée de validité. C’est exp moins iat. Si un token d’accès vit 30 jours, c’est la façon d’émettre les tokens qu’il faut revoir, pas ce token en particulier.
  6. Lisez les avertissements. Le décodeur signale les dates en millisecondes, l’algorithme none et les tokens avec remplissage. Il rappelle aussi qu’il ne vérifie pas la signature.

Exemples concrets (sortie réelle du décodeur)

Nous avons signé ces tokens de test en HS256 avec un secret de démonstration jetable, puis nous les avons collés dans mybotsy.com/fr/jwt-decoder le 31 octobre 2026 vers 15 h 07 UTC, navigateur réglé sur l’heure de Paris.

Exemple 1 : un token expiré

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzg4NDEiLCJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJhdWQiOiJvcmRlcnMtYXBpIiwiaWF0IjoxNzkzMzY4ODAwLCJleHAiOjE3OTMzNzI0MDB9.FJV2oXvW0F-Q7x6rzZRKosQG_DhxLQXXz87wW-Ctq60
LigneSortie du décodeur
StatutExpiré
Émis le (iat)vendredi 30 octobre 2026 à 15:00:00 UTC+1 · 2026-10-30T14:00:00Z · hier · 1793368800
Expire le (exp)vendredi 30 octobre 2026 à 16:00:00 UTC+1 · 2026-10-30T15:00:00Z · hier · 1793372400
Durée de validité1 heure

Les trois bibliothèques sont d’accord. PyJWT a levé ExpiredSignatureError: Signature has expired, jsonwebtoken TokenExpiredError: jwt expired avec expiredAt 2026-10-30T15:00:00.000Z, et jose a renvoyé ERR_JWT_EXPIRED.

Exemple 2 : un token valide collé avec son en-tête

Nous avons collé la ligne entière, Authorization: Bearer eyJhbGciOiJIUzI1NiIs…. Le décodeur a indiqué « Le texte a été nettoyé avant le décodage », puis Non expiré, avec exp le vendredi 1 janvier 2027 à 01:00:00 UTC+1, soit 2027-01-01T00:00:00Z (« dans 2 mois »), et une Durée de validité de 61 jours 9 heures. En France, un token qui expire à minuit UTC le jour de l’An reste donc valable jusqu’à 1 h du matin, heure de Paris. Ne lire que le nombre, ou que la date locale, c’est le meilleur moyen de se tromper d’une heure, voire d’un jour.

Exemple 3 : pas encore valide

Un token avec nbf 1796083200 et exp 1796169600 a donné Pas encore valide, avec Valide à partir du mardi 1 décembre 2026 à 01:00:00 UTC+1 (2026-12-01T00:00:00Z). PyJWT a renvoyé ImmatureSignatureError et jsonwebtoken NotBeforeError: jwt not active. Si un token tout juste émis est refusé, vérifiez nbf et l’horloge du serveur avant d’accuser l’expiration.

Exemple 4 : pas de exp du tout

Le payload {"sub":"svc-reporting","iat":1790856000} a donné Sans expiration (pas de exp), et les trois bibliothèques l’ont accepté. Si un tel token fuite, il reste utilisable jusqu’au changement de clé. Avec PyJWT et options={"require": ["exp"]}, le même token a produit MissingRequiredClaimError: Token is missing the "exp" claim.

Les pièges qui faussent la réponse

exp en millisecondes

L’erreur classique consiste à écrire Date.now() tel quel dans exp. Nous avons signé un token avec "exp":1793462400000. Le décodeur a averti « La valeur de exp semble être en millisecondes » l’a lu en millisecondes et a affiché la vraie date, le 31 octobre 2026 à 16:00 UTC, avec le bon statut et la bonne durée. jsonwebtoken et jose l’ont accepté : en pratique, il n’expire jamais. PyJWT l’a refusé, mais à cause de son contrôle de iat (« The token is not yet valid (iat) »), pas de exp. La correction : divisez par 1000 à l’émission, et multipliez par 1000 pour créer une Date JavaScript à partir de exp.

exp sous forme de texte

"exp":"1798761600", entre guillemets, ne respecte pas la norme. jsonwebtoken l’a refusé avec invalid exp value, et jose avec "exp" claim must be a number. PyJWT l’a accepté tout en l’appliquant : une date passée écrite en texte a bien levé ExpiredSignatureError. Le même token passe donc dans un service et échoue dans un autre. Le décodeur affiche « Date non valide : ce doit être un nombre de secondes » à côté de la valeur, un avertissement, et la ligne Statut indique Expiration illisible : exp n'est pas un nombre valide.

Décalage d’horloge et marge (leeway)

Nous avons créé un token expiré depuis 20 secondes. Sans marge, les trois bibliothèques l’ont refusé. Avec 30 secondes (leeway=30 dans PyJWT, clockTolerance: 30 dans jsonwebtoken et jose), les trois l’ont accepté. Gardez une marge faible : chaque seconde accordée prolonge la vie de tous les tokens, y compris ceux qui ont été volés.

Décoder avec base64 --decode

Les JWT utilisent le base64url, qui remplace + et / par - et _. La commande bien connue cut -d. -f2 | base64 --decode | jq .exp fonctionne jusqu’au jour où le payload contient l’un de ces caractères. Avec GNU coreutils 9.7, un payload contenant - a affiché la moitié du JSON, puis base64: invalid input, et jq a échoué avec Unfinished string. Convertissez d’abord les caractères avec tr '_-' '/+', ou collez le token dans le décodeur, qui lit le base64url nativement. Pour les autres soucis de Base64, voir comment décoder du Base64.

Décoder n’est pas vérifier

N’importe qui peut écrire un token avec un exp en l’an 2100. Lire exp sert à déboguer, ou à décider côté navigateur quand renouveler le token. Avant de faire confiance à une requête, le serveur doit vérifier la signature avec une liste fixe d’algorithmes autorisés. La RFC 8725 décrit des attaques où l’algorithme a été remplacé par none, et notre décodeur affiche un avertissement rouge en cas de alg: none.

Vérifier l’expiration dans le code

Ces fonctions servent à afficher la date ou à planifier le renouvellement, pas à sécuriser. Nous les avons testées sur les tokens ci-dessus : le token expiré a renvoyé true, le token valide et celui en base64url ont renvoyé false, et ceux sans exp ou avec un exp en texte n’ont renvoyé aucune date.

// JavaScript (navigateur ou Node 16+)
function jwtExpiry(token) {
  const part = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
  const { exp } = JSON.parse(atob(part));
  if (typeof exp !== 'number') return null;   // pas de exp, ou exp en texte
  return new Date(exp * 1000);                 // secondes -> ms
}
function isExpired(token, leewaySeconds = 0) {
  const exp = jwtExpiry(token);
  return exp !== null && Date.now() >= exp.getTime() + leewaySeconds * 1000;
}
# Python 3
import base64, json, time

def jwt_exp(token):
    seg = token.split(".")[1]
    seg += "=" * (-len(seg) % 4)   # rétablit le remplissage supprimé par le JWT
    exp = json.loads(base64.urlsafe_b64decode(seg)).get("exp")
    return exp if isinstance(exp, (int, float)) else None

def is_expired(token, leeway=0):
    exp = jwt_exp(token)
    return exp is not None and time.time() >= exp + leeway

La comparaison est « supérieur ou égal », car selon la RFC le token cesse d’être valable à l’instant exp. Côté serveur, appuyez-vous sur la fonction de vérification de votre bibliothèque (jwt.decode avec une clé dans PyJWT, jwt.verify dans jsonwebtoken, jwtVerify dans jose), qui contrôle la signature et les dates en même temps.

Bonnes pratiques de sécurité

  • Traitez un token en cours de validité comme un mot de passe. Tant qu’il n’a pas expiré, celui qui le détient peut agir au nom de l’utilisateur. Préférez un décodeur local comme le nôtre plutôt que de coller des tokens dans un chat ou un ticket.
  • Des tokens d’accès à durée de vie courte, et exp obligatoire côté serveur.
  • Un secret HS256 long et aléatoire. PyJWT a signalé que notre clé de test de 20 octets était « below the minimum recommended length of 32 bytes for SHA256 ». Un secret de 64 caractères tiré du générateur de mots de passe dépasse largement ce seuil. Notre guide pour créer un mot de passe robuste explique pourquoi la longueur compte.
  • Rien de secret dans le payload. Il est seulement encodé, et n’importe qui peut le lire avec un décodeur Base64. Si le payload décodé ne passe pas comme JSON, faites-le passer par le validateur JSON et lisez comment corriger un JSON invalide.

Les certificats expirent aussi. Si l’erreur d’expiration vient du HTTPS et pas d’un token, voir comment vérifier la date d’expiration d’un certificat SSL.

Vérifiez votre token maintenant

Collez-le dans le décodeur JWT gratuit. C’est gratuit et sans compte. Le token reste dans votre navigateur, et vous obtenez le statut, toutes les dates dans votre fuseau et en UTC, et des avertissements pour chacun des pièges ci-dessus.

Questions fréquentes

Comment savoir quand mon JWT expire ?

Décodez le payload et lisez la claim exp, qui compte les secondes depuis le 1er janvier 1970 UTC. Multipliez-la par 1000 pour obtenir une date JavaScript, ou collez le token dans le décodeur JWT de My Botsy, qui affiche exp dans votre fuseau horaire et en UTC.

Un JWT expire-t-il exactement à l’heure de exp ?

Oui. La RFC 7519 précise que le token ne doit plus être accepté à partir de l’heure de exp incluse : comparez donc avec supérieur ou égal. Beaucoup de serveurs ajoutent quelques secondes de marge pour le décalage d’horloge.

Pourquoi le serveur refuse-t-il un token que le décodeur dit non expiré ?

Les causes habituelles sont une horloge serveur différente, un nbf dans le futur, une audience ou un émetteur incorrects, ou une signature invalide. Le décodeur ne lit que les dates. Le serveur, lui, vérifie aussi la signature et les autres claims.

Que se passe-t-il si un JWT n’a pas de exp ?

La plupart des bibliothèques l’acceptent, et le token n’expire jamais de lui-même. Exigez exp côté serveur (par exemple avec l’option require de PyJWT) et gardez des tokens d’accès à courte durée de vie.

Est-il sûr de coller un JWT dans un décodeur en ligne ?

Seulement si le décodeur fonctionne en local. Celui de My Botsy décode dans votre navigateur, et le token n’est jamais envoyé à notre serveur. Traitez malgré tout un token valide comme un mot de passe, et préférez des tokens expirés ou de test pour vos exemples.

Le décodeur JWT de My Botsy est-il gratuit ?

Oui. Il est gratuit, sans compte, et fonctionne dans votre navigateur. Les visiteurs ont 5 utilisations par jour, et un compte gratuit supprime cette limite.

Comment savoir où une photo a été prise (GPS, gratuit)

30 Octobre, 2026

Voyez si une photo révèle où elle a été prise : lisez ses données GPS dans le navigateur, placez les coordonnées sur une carte et effacez la..

Comment savoir si un site est fiable : 6 contrôles gratuits

29 Octobre, 2026

Vérifiez si un site est fiable avant de payer : vrai domaine, âge via WHOIS, certificat SSL, redirections, hébergement et Google Safe Browsi..

Créer un mot de passe robuste facile à retenir

28 Octobre, 2026

Ce qui rend un mot de passe robuste aujourd’hui, comment créer une phrase de passe mémorable et gérer le reste avec un gestionnaire et la 2F..