Message d’erreur
Signature has expired
PyJWT (Python) — jwt.exceptions.ExpiredSignatureError
Ce que cela signifie
Le claim exp du jeton est antérieur à l’heure actuelle du vérificateur : PyJWT l’a donc rejeté après une vérification de signature réussie (du moins conceptuellement). Le message est légèrement trompeur : ce n’est pas la signature elle-même qui expire, c’est la fenêtre de validité du jeton qui s’est refermée.
Pourquoi cela se produit
Jeton périmé réutilisé au-delà de sa durée de vie
fréquenteDes identifiants mis en cache dans un worker de longue durée, un jeton stocké côté client et rejoué après son TTL, ou des tests d’intégration qui utilisent un jeton de fixture généré il y a plusieurs jours. Le rejet est le comportement correct.
Dérive d’horloge sur l’hôte qui vérifie
fréquenteUn vérificateur dont l’horloge avance raccourcit la durée de vie effective de chaque jeton. Les conteneurs et les runners de CI sans synchronisation de l’heure sont les suspects habituels ; même 60 à 120 secondes de dérive suffisent à faire échouer par intermittence les jetons à courte durée de vie.
L’émetteur écrit mal exp
occasionnelleexp doit être un nombre entier de secondes depuis l’epoch. Passer des objets datetime mal sérialisés, ou des millisecondes, produit des jetons déjà expirés au moment de leur émission : chaque vérification échoue alors immédiatement, ce qui distingue ce cas d’une expiration ordinaire.
Datetime naïf (sans fuseau horaire) utilisé pour générer exp
occasionnelleLes émetteurs qui construisent exp à partir de datetime.now() (heure locale naïve) au lieu de datetime.now(timezone.utc) décalent la durée de vie de chaque jeton de l’écart UTC du serveur. Selon le côté de l’UTC où se trouve l’émetteur, les jetons soit expirent plusieurs heures trop tôt, soit survivent discrètement au TTL prévu. PyJWT encode correctement les datetimes avec fuseau horaire : le piège, ce sont les datetimes naïfs.
Comment corriger l’erreur
- 1.
Absorber un faible décalage avec leeway
Le paramètre leeway (en secondes) s’applique aux vérifications des claims exp et nbf. Utilisez quelques dizaines de secondes au maximum ; des valeurs plus élevées prolongent discrètement la durée de vie des jetons.
python import jwt payload = jwt.decode( token, key, algorithms=["ES256"], leeway=30, # seconds of tolerated clock skew ) - 2.
Examiner les horodatages réels
Lisez les claims sans vérification et comparez exp à l’horloge de l’hôte : l’ampleur de l’écart vous indique s’il s’agit d’une expiration, d’un décalage d’horloge ou d’un bug à l’émission.
python import jwt, time claims = jwt.decode(token, options={"verify_signature": False}) print("exp:", claims["exp"], "now:", int(time.time()), "delta:", int(time.time()) - claims["exp"], "s")