Claim 'exp' del JWT: Cómo Corregir Token Caducado
Dev Tools

Claim 'exp' del JWT: Cómo Corregir Token Caducado

Introducción — El Fallo de JWT Más Común

De todos los errores que puede lanzar un JSON Web Token, "token caducado" es el que los desarrolladores encuentran con más frecuencia, y el que con más probabilidad les lleva por el camino equivocado. El síntoma es exasperante: un inicio de sesión que funcionaba perfectamente hace cinco minutos ahora devuelve 401 Unauthorized, el payload parece completamente válido y nada en tu código cambió. Casi siempre, el culpable es un único claim registrado — exp — y un malentendido sobre cómo lo evalúan los verificadores. Esta guía explica exactamente qué es el claim exp, por qué rechaza tokens que parecen correctos y cómo corregir cada variante común del error "token caducado". A lo largo del texto puedes seguir pegando tu token fallido en nuestro Decodificador JWT, que decodifica los claims y convierte las marcas de tiempo en fechas legibles por completo en tu navegador.

Qué Es Realmente el Claim 'exp'

El claim exp (tiempo de expiración) se define en el RFC 7519, Sección 4.1.4, la especificación del IETF para JSON Web Tokens. La especificación es precisa sobre dos cosas que la gente confunde habitualmente. Primero, exp es un NumericDate: el número de segundos — no milisegundos — desde la época Unix (1970-01-01T00:00:00Z), tal como se define en el RFC 7519 Sección 2. Segundo, la regla es simple y absoluta: "la fecha/hora actual DEBE ser anterior al tiempo de expiración indicado en el claim exp." Si now >= exp, el token está caducado y DEBE rechazarse.

Esa palabra "DEBE" importa. Un verificador conforme no es indulgente o estricto por elección; rechazar un token caducado es un comportamiento obligatorio. Por eso no puedes "arreglar" un token caducado reenviándolo — la única respuesta correcta es obtener uno nuevo. El decodificador hace evidente la situación al mostrar el valor de exp como fecha legible e indicar si está en el pasado.

La Causa Número Uno — Milisegundos vs Segundos

El error de exp más frecuente en producción viene de JavaScript. Date.now() devuelve milisegundos, pero el RFC 7519 exige segundos. Un desarrollador que escribe exp: Date.now() + 3600 crea un token que parece caducar dentro de unos 50.000 años, porque el valor en milisegundos se interpreta como segundos. A la inversa, las librerías de firma que emiten correctamente segundos serán malinterpretadas por código de verificación artesanal que compara directamente contra Date.now(), haciendo que cada token parezca caducado.

La solución es estandarizar en segundos en todas partes: Math.floor(Date.now() / 1000) en el cliente, y una comparación de exp contra la misma unidad en el servidor. Cuando pegas un token sospechoso en el Decodificador JWT y la fecha de caducidad aparece como un año muy lejano en el futuro o en 1970, has encontrado un error de unidades de inmediato.

Desfase de Reloj — Cuando Ambos Lados No Coinciden en 'Ahora'

Los errores de "token caducado" más insidiosos ocurren cuando el token es genuinamente reciente pero el reloj del servidor verificador va por delante del emisor. La validación de exp compara una marca de tiempo incrustada en el token contra el reloj local del verificador. Si el reloj del verificador adelanta dos minutos, rechazará tokens a los que aún les quedan dos minutos de vida desde la perspectiva del emisor.

El RFC 7519 anticipó esto. La Sección 4.1.4 permite explícitamente a los implementadores "proporcionar algo de pequeño margen, normalmente no más de unos minutos, para tener en cuenta el desfase de reloj." Este margen (leeway) es la razón por la que la mayoría de las librerías maduras aceptan una tolerancia configurable — a menudo por defecto de 30 o 60 segundos. Si ves rechazos de caducidad intermitentes en un único nodo de un clúster, sospecha del reloj de ese nodo. La solución duradera no es un margen mayor sino una sincronización horaria disciplinada: ejecuta NTP (o chrony) en cada host, y en entornos de contenedores asegúrate de que el reloj del host es correcto, ya que los contenedores lo heredan. Trata el margen como un amortiguador para fluctuaciones de menos de un segundo, nunca como sustituto de relojes sincronizados.

Diagnosticar el Desfase en la Práctica

  • Decodifica el token fallido y anota sus valores de exp e iat como horas absolutas.
  • Compáralos con el reloj del servidor verificador — ejecuta date -u en ese host.
  • Si el "ahora" del servidor supera exp por un margen menor que la vida prevista del token, tienes desfase, no un token genuinamente viejo.

"Caducado Antes de Emitido" y la Trampa de 'nbf'/'iat'

Un pariente confuso del error de caducidad es un token rechazado como aún-no-válido. El claim nbf (not before), RFC 7519 Sección 4.1.5, define el primer momento en que un token puede aceptarse; iat (issued at), Sección 4.1.6, registra cuándo se acuñó. Cuando el reloj del emisor va por detrás del verificador, un token recién creado puede llevar un nbf o iat que parece estar en el futuro desde el punto de vista del verificador, produciendo errores como "token usado antes de emitirse." Esta es la imagen especular del problema de desfase de caducidad y tiene la misma raíz y la misma solución: sincronizar relojes y aplicar un pequeño margen simétrico a nbf además de a exp. Decodificar el token y leer los tres claims de tiempo en paralelo — iat, nbf, exp — es la forma más rápida de ver qué límite se está cruzando.

Claim 'exp' del JWT: Cómo Corregir Token Caducado

El Bucle de Refresco — Cuando la Caducidad Funciona Correctamente

A veces "token caducado" no es un error en absoluto. Los tokens de acceso de vida corta deben caducar, a menudo en cinco a quince minutos, como control de seguridad: un token filtrado solo es útil brevemente. El problema en estos casos no es la caducidad sino un flujo de refresco roto. Si tu token de acceso caduca cada quince minutos y el usuario es expulsado, el refresco silencioso contra tu servidor de autorización está fallando.

Esto produce comúnmente un "bucle de refresco" infinito: el cliente detecta la caducidad, solicita un nuevo token, el refresco en sí falla (a menudo porque el token de refresco tiene su propio exp más largo que también ha caducado, o por una audiencia mal configurada), y el ciclo se repite. Decodifica ambos tokens. Si el exp corto del token de acceso es por diseño pero el exp del token de refresco ha pasado, el usuario genuinamente debe reautenticarse. Si el token de refresco sigue siendo válido, el fallo está en la petición de refresco — con frecuencia un aud no coincidente o una clave de firma rotada — y no en la caducidad. Nuestro artículo complementario sobre decodificar tokens y el análisis a fondo en Tokens JWT Explicados recorren la división token de acceso / token de refresco que subyace a este patrón.

Un Flujo de Corrección Paso a Paso

Cuando aparece un error de "token caducado", resiste la tentación de ampliar las vidas a ciegas. Trabaja el problema en orden:

  • Decodifica primero. Pega el token en el Decodificador JWT y lee exp como fecha. ¿Está realmente en el pasado, o se lee como 1970 / el año 50.000? Una fecha sin sentido es un error de unidades.
  • Comprueba la unidad. Confirma que emisor y verificador tratan exp como segundos. Sustituye cualquier comparación con Date.now() por Math.floor(Date.now()/1000).
  • Comprueba los relojes. Ejecuta date -u en los hosts emisor y verificador. Sincroniza con NTP si difieren.
  • Comprueba el margen. Asegúrate de que tu librería aplica una tolerancia de desfase moderada (30–60s) según el RFC 7519 §4.1.4 — pero arregla los relojes en lugar de inflar el margen.
  • Comprueba la ruta de refresco. Si la caducidad es por diseño, verifica que el exp, el aud y la clave de firma del propio token de refresco son válidos.
  • Verifica la firma. Un token que falla la verificación por una razón no relacionada puede aflorar como un error de auth genérico confundido con caducidad; confirma que la firma se sostiene antes de culpar al reloj.

Notas de Seguridad — No Arregles la Caducidad de Forma Equivocada

La "solución" tentadora para el dolor repetido de la caducidad es extender la vida del token de acceso a horas o días. Resístete. Un token de acceso de vida larga convierte cualquier filtración en una credencial duradera que un atacante puede reproducir hasta que finalmente caduque, y a diferencia de una sesión no puede revocarse al instante porque un JWT firmado sigue siendo válido hasta su exp con independencia del estado del servidor. La guía de OWASP sobre gestión de sesiones y tokens es consistente en este punto: mantén los tokens de acceso cortos, traslada la longevidad a un token de refresco protegido por separado, y nunca amplíes exp para tapar un flujo de refresco roto.

Igual de importante: nunca pegues un token de producción activo en un decodificador online del lado del servidor, que transmite tu credencial activa a un tercero. Una herramienta del lado del cliente que procesa todo en el navegador — como la nuestra — mantiene el token en tu máquina mientras depuras.

Conclusión

El claim exp del JWT es implacable por diseño: el RFC 7519 obliga a rechazar un token caducado, así que la respuesta nunca es persuadir al verificador para que lo acepte sino entender por qué se lee como caducado. En la práctica la causa es casi siempre una de cuatro cosas — milisegundos confundidos con segundos, desfase de reloj entre hosts, un nbf/iat con fecha futura de un emisor retrasado, o un flujo de refresco que falla mientras la caducidad se comporta exactamente como se pretendía. Cada una es diagnosticable en segundos decodificando el token y leyendo sus claims de tiempo como fechas reales. Mantén abierto el Decodificador JWT mientras depuras, usa el Formateador JSON cuando un payload sea denso, y revisa Tokens JWT Explicados para el modelo mental completo. Todo permanece en tu navegador, así que incluso los tokens de producción nunca salen de tu máquina.

← Volver al Blog