Expiration JWT et claims "émis à" : comment les timestamps Unix alimentent l'auth par token

Revendications d'expiration JWT exp et iat affichées comme horodatages Unix dans un diagramme de payload JWT

À chaque connexion d'un utilisateur à une application SaaS, un token d'authentification est généré et transmis à son navigateur ou à son application mobile. Ce token embarque une horloge silencieuse. Le champ d'expiration JWT, stocké sous forme d'un timestamp Unix brut, indique à chaque serveur qui le lit à quel moment précis il doit cesser de faire confiance à ce credential. Une erreur de quelques secondes sur ce timestamp peut verrouiller des utilisateurs trop tôt ou, pire, leur laisser une session active bien au-delà de ce que ta politique de sécurité autorise. Comprendre le fonctionnement des claims d'un JSON web token - en particulier exp et iat - est l'une des choses les plus concrètes qu'une équipe SaaS puisse faire pour renforcer l'authentification sans alourdir l'expérience utilisateur.

Points clés à retenir :

  • Les claims exp et iat d'un JWT JSON web token sont toujours des timestamps Unix exprimés en secondes entières, jamais en millisecondes.
  • Le décalage d'horloge entre serveurs peut invalider silencieusement des tokens ou prolonger des sessions au-delà de la politique définie - une tolérance de 60 secondes est la correction standard du secteur.
  • Une durée d'expiration de token trop longue augmente le risque en cas de compromission ; trop courte, elle dégrade l'expérience utilisateur. Une formule concrète t'aide à choisir la bonne valeur.
  • Tu peux décoder et vérifier n'importe quel timestamp d'un JSON web token en secondes grâce à un convertisseur d'epoch Unix, sans aucune librairie.

Qu'est-ce qu'un JWT et pourquoi les timestamps y sont intégrés

Un JSON web token est un credential compact et compatible URL, composé de trois parties encodées en Base64 séparées par des points : un header, un payload et une signature. C'est dans le payload que résident les données sensibles au temps. Parce que les JWT sont stateless, le serveur n'effectue aucune requête en base de données pour les valider. Il lit directement les claims intégrés dans le payload et se fie à la signature cryptographique. Cette architecture est rapide et scalable, mais elle impose une contrainte réelle : une fois un token émis, le serveur ne peut pas le "supprimer". La seule façon fiable de limiter sa durée de vie est d'y intégrer directement un timestamp d'expiration.

C'est pourquoi le temps - plus précisément l'epoch Unix - est au coeur de la sécurité JWT. La spécification RFC 7519 qui définit les JWT impose que les claims temporels soient exprimés sous forme de valeurs "NumericDate", c'est-à-dire le nombre de secondes écoulées depuis le 1er janvier 1970 UTC. Pas de fuseau horaire. Pas de formatage régional. Juste un entier que n'importe quel serveur, où qu'il soit dans le monde, peut comparer à sa propre horloge.

Structure d'un JWT montrant le header, le payload et la signature avec les claims exp et iat

Les claims exp et iat expliqués

La spécification JWT définit plusieurs claims enregistrés. Deux d'entre eux sont essentiels pour gérer le cycle de vie d'un token :

  • exp (Expiration Time) : Le timestamp après lequel le token ne doit plus être accepté. Les serveurs sont tenus de rejeter tout token dont le temps actuel est supérieur ou égal à cette valeur. C'est le mécanisme central de l'expiration JWT.
  • iat (Issued At) : Le timestamp auquel le token a été créé. Le claim iat n'est pas vérifié par défaut, mais il est extrêmement utile. Il te permet de calculer l'âge d'un token, d'appliquer une politique d'âge maximum indépendamment de exp , et de détecter des tokens émis de façon suspecte dans le passé lointain.

Un troisième claim, nbf (Not Before), définit la date la plus précoce à partir de laquelle un token est valide. Il est moins courant, mais suit le même format de timestamp Unix.

Ces trois valeurs sont des entiers. Si ton système les génère en millisecondes - erreur fréquente avec Date.now() en JavaScript - le nombre obtenu sera environ 1 000 fois trop grand. Un serveur qui compare exp à l'epoch actuelle en secondes verra un token dont l'expiration semble fixée à l'an 33 658 et ne le rejettera jamais. Ce bug en production a déjà touché plusieurs équipes SaaS.

Exemple concret : décoder de vrais timestamps de token

Supposons que ton service d'authentification émette le payload JWT suivant après qu'un utilisateur se connecte à 10h00 UTC le 1er juillet 2025 :

{
  "sub": "user_8821",
  "iat": 1751364000,
  "exp": 1751367600,
  "role": "admin"
}

Voici ce que ces nombres signifient :

Claim Timestamp Unix Lisible (UTC) Signification
iat 1751364000 2025-07-01 10:00:00 Token émis à cet instant
exp 1751367600 2025-07-01 11:00:00 Token expire exactement 1 heure plus tard

La différence est exactement 3 600 secondes, soit une heure. Tout serveur qui reçoit ce token après 11:00:00 UTC doit le rejeter. Pour le vérifier manuellement, il suffit de soustraire iat de exp : 1751367600 - 1751364000 = 3600 secondes. Tu peux confirmer l'équivalent lisible de ces valeurs en un instant grâce à un convertisseur de timestamp Unix - exactement le genre de vérification rapide qui évite le bug millisecondes/secondes mentionné plus haut.

Pour aller plus loin sur la façon dont les bases de données doivent stocker ces valeurs, consulte notre guide sur les timestamps Unix en base de données, car le même format entier s'applique que tu stockes exp dans un token ou dans une table de journalisation.

Le décalage d'horloge, ennemi silencieux des tokens

Voici une contrainte réelle qui prend les équipes par surprise. Dans un système distribué, ton serveur d'authentification et ton serveur API sont deux machines distinctes. Leurs horloges système sont synchronisées via NTP, mais elles ne sont jamais parfaitement alignées. Un écart de 30 à 90 secondes est courant dans les environnements cloud.

Considère ce scénario : un token avec exp = 1751367600 est validé par un serveur API dont l'horloge indique 1751367610, soit seulement 10 secondes après l'expiration. Le token est rejeté. L'utilisateur reçoit une erreur 401. De son point de vue, il venait juste de se connecter et l'application a planté.

La correction standard consiste à intégrer une tolérance de décalage d'horloge dans ta logique de validation. La plupart des librairies JWT proposent un paramètre de marge. Une valeur de 60 secondes est largement acceptée et référencée dans la spécification OpenID Connect Core. Configure-la, documente-la, et assure-toi que tous les services de ta stack utilisent la même valeur.

Règle pratique : Applique une marge de 60 secondes à la validation de exp . N'ajoute jamais de marge aux vérifications de iat , car cela reviendrait à accepter des tokens émis dans le futur - ce qui est un signal d'alarme pour les attaques par rejeu.

Choisir la bonne durée d'expiration pour ton produit SaaS

La bonne valeur d'expiration de token dépend de la sensibilité de ton application et du comportement de session attendu. Voici un cadre pratique :

  • Applications à haute sensibilité (banque, santé, tableaux de bord d'administration) : 15 à 30 minutes pour les access tokens. Utilise des refresh tokens pour renouveler les sessions silencieusement.
  • Applications SaaS standard (gestion de projet, CRM, analytics) : 1 à 8 heures. Aligne la durée sur la longueur typique d'une session de travail.
  • API à faible risque ou en lecture seule : Jusqu'à 24 heures, mais associe à une rotation de token sur les actions sensibles.
  • Tokens de service machine-à-machine : Peuvent être plus longs (jours ou semaines), mais doivent avoir un périmètre restreint et être renouvelés selon un calendrier défini.

Une formule utile pour calculer ta valeur exp au moment de l'émission :

// Exemple Node.js
const iat = Math.floor(Date.now() / 1000); // temps actuel en secondes
const ttl = 3600; // time-to-live : 1 heure en secondes
const exp = iat + ttl;

const payload = {
  sub: userId,
  iat: iat,
  exp: exp
};

Remarque la division explicite par 1000 pour convertir les millisecondes en secondes. Cette seule ligne évite le bug de timestamp JWT le plus répandu dans les applications JavaScript.

Étapes concrètes pour implémenter une expiration JWT sécurisée

Voici une checklist concrète applicable dès aujourd'hui à n'importe quel système d'authentification SaaS :

  1. Inclure toujours les deux claims iat et exp . Le claim iat est techniquement optionnel, mais il fournit une piste d'audit et permet d'appliquer une politique d'âge maximum indépendamment de l'expiration.
  2. Vérifier le format du timestamp avant de déployer. Décode ton token et contrôle que exp est un entier à 10 chiffres. Une valeur à 13 chiffres signifie que des millisecondes se sont glissées dans le calcul.
  3. Configurer une marge de décalage d'horloge de 60 secondes dans ton middleware de validation. Applique-la de façon cohérente sur chaque service qui consomme des tokens d'authentification.
  4. Utiliser des access tokens de courte durée avec des refresh tokens. Un access token de 15 minutes associé à un refresh token de 7 jours est bien plus sécurisé qu'un unique access token de 7 jours, car le refresh token peut être révoqué côté serveur.
  5. Journaliser la valeur iat à chaque requête authentifiée. Cela te permet de détecter des anomalies, comme le même token utilisé simultanément depuis deux régions géographiques différentes.
  6. Tester l'expiration en staging avec un temps accéléré. Simule un saut d'horloge au-delà de la valeur exp et vérifie que ton application gère l'erreur 401 correctement, sans planter ni boucler.

Si tu as besoin de convertir rapidement une valeur brute exp extraite d'un token en date lisible, ou de vérifier quel timestamp définir pour une durée donnée, le convertisseur d'epoch sur notre page d'accueil gère les deux sens instantanément, sans aucun code.

Conclusion

L'expiration JWT n'est pas un concept complexe, mais c'est un domaine où de petites erreurs créent de grandes failles de sécurité. Les claims exp et iat ne sont que des entiers - des timestamps Unix comptés en secondes depuis l'epoch. Cette simplicité est leur force : chaque serveur, chaque langage et chaque plateforme peut comparer deux nombres sans ambiguïté. La vraie compétence réside dans leur bonne application : choisir une durée d'expiration de token sensée, gérer le décalage d'horloge avec une fenêtre de tolérance, et détecter l'erreur millisecondes/secondes avant qu'elle parte en production. Intègre ces bonnes pratiques dans ton pipeline d'authentification et ton implémentation de JSON web token sera à la fois sécurisée et maintenable.

Outil de conversion de timestamp Unix pour vérifier l'expiration JWT

Vérifie tes timestamps JWT instantanément - sans écrire une ligne de code

Colle n'importe quel timestamp Unix extrait d'un payload JWT et convertis-le en date lisible en un clic. Détecte les erreurs millisecondes/secondes avant qu'elles atteignent la production.

Essayer l'outil gratuit →

exp (Expiration Time) est le timestamp Unix après lequel le token est invalide et doit être rejeté. iat (Issued At) est le timestamp auquel le token a été créé. Ces deux valeurs sont des entiers en secondes. Le claim iat est optionnel, mais précieux pour l'audit et l'application de politiques d'âge maximum des tokens.

Les timestamps Unix sont des entiers indépendants du fuseau horaire, ce qui les rend non ambigus sur tous les serveurs et dans toutes les régions. Des chaînes de date formatées comme "2025-07-01T10:00:00" peuvent être mal interprétées selon les paramètres régionaux ou de fuseau horaire. La comparaison de deux entiers est aussi plus rapide et moins sujette aux erreurs que le parsing de chaînes dans des systèmes d'authentification à fort débit.

Un token à longue durée de vie reste valide même si le compte de l'utilisateur est compromis ou si ses permissions changent. Les JWT étant stateless, le serveur ne peut pas les révoquer en cours de vie. Si un attaquant vole un token avec une expiration de 30 jours, il dispose de 30 jours d'accès. Des fenêtres d'expiration courtes combinées à des refresh tokens réduisent considérablement ce risque.

En JavaScript, utilise toujours Math.floor(Date.now() / 1000) pour générer les valeurs iat ou exp . La fonction brute Date.now() retourne des millisecondes. La division par 1000 la convertit en entier en secondes, comme l'exige la spécification JWT. Vérifie que ton timestamp est bien un nombre à 10 chiffres et non à 13 chiffres.

Le décalage d'horloge est la petite différence de temps entre les horloges système de deux serveurs dans un système distribué. Même un écart de 30 secondes peut provoquer le rejet d'un token valide si l'horloge du serveur de validation est légèrement en avance. La correction standard consiste à configurer une marge de 60 secondes dans ta librairie de validation JWT pour absorber la dérive NTP normale.