Guías JWT

Cómo compruebo el claim exp y la expiración de un JWT

Cómo leo exp como NumericDate, manejo segundos y milisegundos correctamente, comparo el reloj del verifier y clock skew y decido si expiration es realmente la causa.

Por JWTDecoder.toolsÚltima verificación 2026-09-16

Voz editorial: la primera persona describe el flujo de trabajo documentado de JWTDecoder.tools; JWTDecoder.tools es el editor y autor organizacional.

Línea temporal JWT con iat, nbf, ventana activa y exp
Reviso iat, nbf, ventana activa y exp antes de atribuir el problema a la expiración.

Cuando veo token expired, jwt expired o un 401 que parece temporal, compruebo exp temprano pero no lo analizo aislado. Convierto el valor, lo comparo con el reloj del sistema que valida y miro también iat y nbf. Así separo expiración real de unidades equivocadas, clock skew y políticas adicionales.

Para una lectura rápida uso JWT Expiry Checker.

exp es NumericDate en segundos

RFC 7519 define exp como Expiration Time:

{
  "iat": 1789200000,
  "nbf": 1789200000,
  "exp": 1789203600
}

Conceptualmente:

current verifier time < exp

Cuando el reloj del verifier alcanza o supera exp, un perfil que aplica expiración debe rechazarlo, salvo una pequeña tolerancia explícita.

El error clásico: segundos contra milisegundos

const now = Math.floor(Date.now() / 1000);
const expired = typeof payload.exp === "number" && now >= payload.exp;

También puede hacerse:

const expired = Date.now() >= payload.exp * 1000;

Lo que no hago es comparar Date.now() directamente con payload.exp.

Cómo lo compruebo en Python

import time
if isinstance(payload.get("exp"), (int, float)) and time.time() >= payload["exp"]:
    raise ValueError("token expired")

Estos snippets explican tiempo, no sustituyen una librería de verificación de firma y claims.

Clock skew: tolerancia pequeña, no extensión arbitraria

RFC 7519 permite una pequeña leeway por diferencias de reloj. La uso solo cerca del límite:

exp             12:00:00Z
verifier clock  12:00:03Z
leeway          5s

Si exp quedó 45 minutos atrás, clock skew no es una explicación razonable.

Leo iat, nbf y exp como una línea temporal

issued -------- active window -------- expired
  iat     nbf                     exp

Señales sospechosas:

  • nbf > exp;
  • iat muy en el futuro;
  • exp < iat;
  • lifetime inesperadamente largo;
  • todos los valores desplazados por factor 1000.

JWT Validator me ayuda a ver estas reglas junto a firma e issuer/audience.

Missing exp depende del perfil

RFC 7519 define el claim, pero cada perfil decide qué es obligatorio. RFC 7523, por ejemplo, sí impone exp en su contexto.

Antes de marcarlo como error pregunto:

  1. qué tipo de token es;
  2. qué perfil aplica;
  3. si la API exige expiración;
  4. si hay maximum token age adicional.

Un token puede estar dentro de exp y aun así fallar

Otras causas:

  • firma inválida;
  • nbf futuro;
  • iss equivocado;
  • aud equivocado;
  • token type incorrecto;
  • scopes/roles insuficientes;
  • revocation/session policy.

Si el tiempo está bien, uso JWT Debugger en lugar de seguir culpando a exp.

Editar exp no renueva un JWT firmado

Cambiar:

{ "exp": 1789203600 }

por otro timestamp cambia el payload firmado. La firma anterior debe dejar de ser válida. El renewal correcto emite un token nuevo.

Matriz de diagnóstico

ObservaciónInterpretaciónSiguiente paso
now >= expexpiración probablerefresh/reauthentication
diferencia de pocos segundosposible skewrevisar clocks/leeway
nbf > nowaún no activorevisar emisión/reloj
iat en futuroclock/unidadrevisar infraestructura
exp ausentepolicy del perfilconsultar especificación
exp futuro + 401otra validaciónfirma/iss/aud

Mi flujo de comprobación

  1. Decodifico el JWT con JWT Decoder.
  2. Confirmo que exp es numérico y está en segundos.
  3. Convierto a UTC.
  4. Comparo con el reloj del verifier real.
  5. Reviso iat y nbf.
  6. Compruebo clock tolerance explícita.
  7. Confirmo si el perfil exige exp.
  8. Si está expirado, uso el mecanismo legítimo de renewal.
  9. Si sigue activo, paso a firma, issuer y audience.

exp responde si el token está fuera de su ventana temporal. No responde por sí solo si una aplicación debe confiar en él.

Registro el contexto de cada rechazo

Cuando un verifier rechaza un token, conservo el valor de exp, la hora UTC observada, la tolerancia aplicada y el componente que tomó la decisión. También comparo el mismo token contra un entorno conocido, sin copiarlo en logs públicos. Este contexto permite distinguir un error de unidad, un reloj desfasado o una política de duración máxima de una expiración real y reproducible.

Antes de modificar la tolerancia, repito la comparación con una hora de referencia independiente y confirmo que todos los servicios usan segundos Unix. Si un gateway y una API toman decisiones distintas, reviso sus configuraciones por separado: compartir el mismo JWT no garantiza que compartan reloj, profile ni política de validación.

Fuentes y referencias

Guías relacionadas