Expiración de JWT y Claims de Emisión: Cómo los Timestamps Unix Impulsan la Autenticación con Tokens

Diagrama de carga útil JWT con claims de expiración exp e iat como marcas de tiempo Unix

Cada vez que un usuario inicia sesión en una aplicación SaaS, se genera un token de autenticación que se envía al navegador o a la app móvil. Ese token lleva un reloj silencioso en su interior. El campo de expiración del JWT, almacenado como un timestamp Unix simple, le indica a cada servidor que lo lee exactamente cuándo dejar de confiar en esa credencial. Si ese timestamp está mal por apenas unos segundos, los usuarios quedan bloqueados antes de tiempo o, peor aún, mantienen una sesión válida mucho más de lo que tu política de seguridad permite. Entender cómo funcionan los claims de un JSON web token, especialmente exp e iat , es una de las cosas más prácticas que puede hacer un equipo SaaS para reforzar la autenticación sin generar fricción.

Puntos clave:

  • Los claims exp e iat en un JWT JSON web token son siempre timestamps Unix medidos en segundos enteros, no en milisegundos.
  • El desfase de reloj entre servidores puede invalidar tokens silenciosamente o extender sesiones más allá de lo permitido por la política - una ventana de tolerancia de 60 segundos es la solución estándar del sector.
  • Configurar una expiración de token demasiado larga aumenta el riesgo ante brechas de seguridad; demasiado corta arruina la experiencia del usuario. Una fórmula concreta te ayuda a elegir el valor correcto.
  • Puedes decodificar y verificar cualquier timestamp de un JSON web token en segundos usando un conversor de época Unix, sin necesidad de ninguna librería.

Qué es un JWT y por qué lleva timestamps en su interior

Un JSON web token es una credencial compacta y segura para URLs, formada por tres partes codificadas en Base64 separadas por puntos: un header, un payload y una firma. El payload es donde viven los datos sensibles al tiempo. Como los JWT son stateless, el servidor no consulta ninguna base de datos para validarlos. En cambio, lee los claims incluidos en el payload y confía en la firma criptográfica. Ese diseño es rápido y escalable, pero impone una restricción real: una vez emitido el token, el servidor no puede "eliminarlo". La única forma fiable de limitar su vida útil es incrustar directamente un timestamp de expiración dentro del propio token.

Por eso el tiempo, concretamente el tiempo epoch Unix, es fundamental para la seguridad de los JWT. La especificación RFC 7519 que define los JWT exige que los claims relacionados con el tiempo se expresen como valores "NumericDate", que son simplemente el número de segundos transcurridos desde el 1 de enero de 1970 UTC. Sin zonas horarias. Sin formatos locales. Solo un entero que cualquier servidor en cualquier parte del mundo puede comparar con su propio reloj.

Estructura de un JWT mostrando header, payload y firma con los claims exp e iat

Los claims exp e iat explicados

La especificación JWT define varios claims registrados. Dos son los más importantes para gestionar el ciclo de vida de un token:

  • exp (Expiration Time): El timestamp a partir del cual el token no debe aceptarse. Los servidores están obligados a rechazar cualquier token en el que el tiempo actual sea igual o mayor que este valor. Este es el mecanismo central de la expiración del JWT.
  • iat (Issued At): El timestamp en el que se creó el token. El claim iat no se aplica de forma obligatoria por defecto, pero resulta enormemente útil. Te permite calcular la antigüedad de un token, aplicar una política de edad máxima de forma independiente a exp , y detectar tokens que fueron emitidos de forma sospechosamente lejana en el pasado.

Un tercer claim, nbf (Not Before), define el momento más temprano en que un token es válido. Se usa con menos frecuencia, pero sigue el mismo formato de timestamp Unix.

Los tres valores son enteros. Si tu sistema los genera en milisegundos (un error habitual al usar Date.now() de JavaScript), el número resultante será aproximadamente 1.000 veces mayor de lo esperado. Un servidor que compara exp con el segundo epoch actual verá un token que aparentemente expira en el año 33.658 y nunca lo rechazará. Este es un bug real en producción que ha afectado a múltiples equipos SaaS.

Un ejemplo real: decodificando timestamps de tokens

Supongamos que tu servicio de autenticación emite el siguiente payload JWT después de que un usuario inicia sesión a las 10:00 AM UTC del 1 de julio de 2025:

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

Veamos qué significan esos números:

Claim Timestamp Unix Legible por humanos (UTC) Significado
iat 1751364000 2025-07-01 10:00:00 El token fue emitido en este momento
exp 1751367600 2025-07-01 11:00:00 El token expira exactamente 1 hora después

La diferencia es exactamente 3.600 segundos, es decir, una hora. Cualquier servidor que reciba este token después de las 11:00:00 UTC debe rechazarlo. Para verificarlo manualmente, resta iat de exp : 1751367600 - 1751364000 = 3600 segundos. Puedes confirmar el equivalente legible de cualquiera de estos valores al instante usando un conversor de timestamps Unix, que es exactamente el tipo de comprobación rápida que evita el bug de milisegundos frente a segundos mencionado antes.

Para más contexto sobre cómo deberían almacenarse estos valores en bases de datos, consulta nuestra guía sobre timestamps Unix en bases de datos, ya que el mismo formato entero aplica tanto si almacenas exp en un token como en una tabla de auditoría.

Desfase de reloj: el enemigo silencioso de los tokens

Aquí hay una limitación real que sorprende a muchos equipos. En un sistema distribuido, tu servidor de autenticación y tu servidor de API son dos máquinas distintas. Sus relojes del sistema están sincronizados mediante NTP, pero nunca están perfectamente alineados. Una diferencia de 30 a 90 segundos es habitual en entornos cloud.

Considera este escenario: un token con exp = 1751367600 es validado por un servidor de API cuyo reloj marca 1751367610, apenas 10 segundos después de la expiración. El token es rechazado. El usuario recibe un error 401. Desde su perspectiva, acaba de iniciar sesión y la aplicación falló sin motivo aparente.

La solución estándar es incorporar una tolerancia al desfase de reloj en tu lógica de validación. La mayoría de las librerías JWT admiten un parámetro de margen (leeway). Un valor de 60 segundos es ampliamente aceptado y está referenciado en la especificación OpenID Connect Core. Configúralo, documéntalo y asegúrate de que todos los servicios de tu stack usen el mismo valor.

Regla práctica: Añade un margen de 60 segundos a la validación de exp . Nunca añadas margen a las comprobaciones de iat , porque eso permitiría aceptar tokens emitidos en el futuro, lo cual es una señal de alerta para ataques de replay.

Cómo elegir la expiración de token correcta para tu producto SaaS

El valor correcto de expiración de token depende de la sensibilidad de tu aplicación y del comportamiento esperado de la sesión. Aquí tienes un marco práctico:

  • Apps de alta sensibilidad (banca, salud, paneles de administración): 15 a 30 minutos para los access tokens. Usa refresh tokens para renovar sesiones de forma silenciosa.
  • Apps SaaS estándar (gestión de proyectos, CRM, analítica): 1 a 8 horas. Ajústalo a la duración típica de una jornada de trabajo.
  • APIs de bajo riesgo o de solo lectura: Hasta 24 horas, pero combínalo con rotación de tokens en acciones sensibles.
  • Tokens de servicio máquina a máquina: Pueden tener mayor duración (días o semanas), pero deben tener un scope reducido y rotarse de forma programada.

Una fórmula útil para calcular el valor de exp en el momento de emisión:

// Ejemplo en Node.js
const iat = Math.floor(Date.now() / 1000); // tiempo actual en segundos
const ttl = 3600; // time-to-live: 1 hora en segundos
const exp = iat + ttl;

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

Fíjate en la división explícita por 1000 para convertir de milisegundos a segundos. Esta única línea previene el bug de timestamp JWT más común en aplicaciones JavaScript.

Pasos concretos para implementar una expiración JWT segura

Aquí tienes una lista de verificación concreta que puedes aplicar hoy mismo a cualquier sistema de autenticación SaaS:

  1. Incluye siempre tanto iat como exp . El claim iat es técnicamente opcional, pero te proporciona una traza de auditoría y permite aplicar una política de edad máxima independiente de la expiración.
  2. Verifica el formato del timestamp antes de desplegar. Decodifica tu token y comprueba que exp sea un entero de 10 dígitos. Un valor de 13 dígitos significa que se han colado milisegundos.
  3. Configura un margen de desfase de reloj de 60 segundos en tu middleware de validación. Aplícalo de forma consistente en todos los servicios que consumen tokens de autenticación.
  4. Usa access tokens de corta duración combinados con refresh tokens. Un access token de 15 minutos junto con un refresh token de 7 días es mucho más seguro que un único access token de 7 días, porque el refresh token puede revocarse del lado del servidor.
  5. Registra el valor de iat en cada solicitud autenticada. Esto te permite detectar anomalías, como el mismo token siendo usado simultáneamente desde dos regiones geográficas distintas.
  6. Prueba la expiración en staging con tiempo acelerado. Simula que el reloj avanza más allá del valor de exp y confirma que tu app gestiona el error 401 de forma elegante, sin caídas ni bucles infinitos.

Si necesitas convertir rápidamente un valor de exp en bruto de un token a una fecha legible, o verificar qué timestamp establecer para una duración determinada, el conversor de época en nuestra página de inicio lo resuelve en ambas direcciones al instante, sin necesidad de código.

Conclusión

La expiración de JWT no es un concepto complejo, pero es uno donde los pequeños errores generan grandes brechas de seguridad. Los claims exp e iat son simplemente enteros, timestamps Unix contados en segundos desde el epoch. Esa simplicidad es su fortaleza: cualquier servidor, cualquier lenguaje y cualquier plataforma puede comparar dos números sin ambigüedad. La habilidad real está en aplicarlos correctamente: elegir una duración de expiración de token sensata, gestionar el desfase de reloj con una ventana de tolerancia, y detectar el error de milisegundos frente a segundos antes de que llegue a producción. Incorpora estos hábitos en tu pipeline de autenticación y tu implementación de JSON web token será tanto segura como mantenible.

Herramienta de conversión de timestamps Unix para verificar la expiración de JWT

Verifica timestamps JWT al instante - sin código

Pega cualquier timestamp Unix de un payload JWT y conviértelo a una fecha legible con un solo clic. Detecta errores de milisegundos frente a segundos antes de que lleguen a producción.

Prueba nuestra herramienta gratuita →

exp (Expiration Time) es el timestamp Unix a partir del cual el token es inválido y debe rechazarse. iat (Issued At) es el timestamp en el que se creó el token. Ambos son enteros en segundos. El claim iat es opcional, pero resulta muy útil para auditoría y para aplicar políticas de edad máxima de los tokens.

Los timestamps Unix son enteros independientes de la zona horaria, lo que los hace inequívocos en todos los servidores y regiones. Las cadenas de fecha formateadas como "2025-07-01T10:00:00" pueden interpretarse de forma distinta según la configuración regional o de zona horaria. Además, comparar enteros es más rápido y menos propenso a errores que parsear cadenas en sistemas de autenticación de alto rendimiento.

Un token de larga duración sigue siendo válido aunque la cuenta del usuario haya sido comprometida o sus permisos hayan cambiado. Como los JWT son stateless, el servidor no puede revocarlos durante su vida útil. Si un atacante roba un token con 30 días de expiración, tiene 30 días de acceso. Combinar ventanas de expiración cortas con refresh tokens reduce significativamente esta ventana de riesgo.

En JavaScript, usa siempre Math.floor(Date.now() / 1000) al generar los valores de iat o exp . El método Date.now() sin modificar devuelve milisegundos. Dividir entre 1000 lo convierte al entero en segundos que requiere la especificación JWT. Verifica que tu timestamp sea un número de 10 dígitos y no de 13.

El desfase de reloj es la pequeña diferencia de tiempo entre los relojes del sistema de dos servidores en un entorno distribuido. Incluso una diferencia de 30 segundos puede hacer que un token válido sea rechazado si el reloj del servidor que lo valida va ligeramente adelantado. La solución estándar es configurar un margen (leeway) de 60 segundos en tu librería de validación JWT para absorber la deriva normal de NTP.