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
expeiaten 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.
Tabla de contenidos
- Qué es un JWT y por qué lleva timestamps en su interior
-
Los claims
expeiatexplicados - Un ejemplo real: decodificando timestamps de tokens
- Desfase de reloj: el enemigo silencioso de los tokens
- Cómo elegir la expiración de token correcta para tu producto SaaS
- Pasos concretos para implementar una expiración JWT segura
- Conclusión
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.
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 aexp, 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:
-
Incluye siempre tanto
iatcomoexp. El claimiates 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. -
Verifica el formato del timestamp antes de desplegar.
Decodifica tu token y comprueba que
expsea un entero de 10 dígitos. Un valor de 13 dígitos significa que se han colado milisegundos. - 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.
- 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.
-
Registra el valor de
iaten cada solicitud autenticada. Esto te permite detectar anomalías, como el mismo token siendo usado simultáneamente desde dos regiones geográficas distintas. -
Prueba la expiración en staging con tiempo acelerado.
Simula que el reloj avanza más allá del valor de
expy 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.
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.