← Volver al Blog

Errores de JWT exp/iat/nbf: errores de reclamación de tiempo que rompen la autenticación

Seguridad del desarrollador27 de marzo de 2026·8 min de lectura
JWT time claims debugging
Los reclamos de tiempo

JWT (exp, iat y nbf) son engañosamente simples. Son sólo marcas de tiempo de Unix. Sin embargo, causan algunos de los errores de autenticación más frustrantes en producción: tokens que caducan demasiado pronto, tokens que funcionan en un servidor pero no en otro y tokens que nunca caducan.

Este artículo cubre los errores más comunes en la reclamación de tiempo, por qué ocurren y cómo solucionarlos con valores predeterminados seguros.

Cómo funcionan exp, iat y nbf

Cada JWT puede llevar tres reclamos relacionados con el tiempo en su carga útil:

Los tres son fechas numéricas: el número de segundos desde 1970-01-01T00:00:00Z (época Unix). No milisegundos, segundos. Esta distinción por sí sola causa aproximadamente el 20 % de todos los errores de tiempo de JWT.

Utilice nuestro JWT Decoder para inspeccionar los reclamos de tiempo en cualquier token al instante.

Error #1: Usar milisegundos en lugar de segundos

JavaScript Date.now() devuelve milisegundos. La especificación JWT requiere segundos. Configurar exp en Date.now() + 3600000 crea un token que vence en el año 2089, no en una hora.

// INCORRECTO — milisegundos
exp constante = Fecha.ahora() + 3600000; // CORRECTO - segundos
const exp = Math.floor(Fecha.ahora() / 1000) + 3600;

La mayoría de las bibliotecas JWT manejan esto internamente, pero si estás creando cargas útiles manualmente, esto es lo primero que debes verificar.

Error #2: Falta el reclamo de exp por completo

Si olvida configurar exp, muchas bibliotecas crearán felizmente un token que nunca caduca. Esto supone un riesgo para la seguridad: un token filtrado sigue siendo válido para siempre.

Siempre establece exp. Validarlo siempre en el servidor. Si su biblioteca no rechaza tokens sin exp de forma predeterminada, configúrela para hacerlo.

// Node.js jsonwebtoken: aplicar la caducidad
jwt.verify(token, secreto, { maxAge: '1h' });

Error nº 3: Desviación del reloj entre servidores

El servidor A emite un token a las 14:00:00. El reloj del servidor B marca las 13:59:55 (5 segundos de retraso). Si el token tiene nbf: 1711540800 (14:00:00), el servidor B lo rechaza como "aún no válido".

Esto es especialmente común en:

La solución

Permita una pequeña tolerancia de reloj (también llamada "margen de maniobra"), normalmente entre 30 y 60 segundos:

// jsonwebtoken
jwt.verify(token, secreto, { clockTolerance: 30 }); // josé (Node.js)
espere jwtVerify(token, clave, { clockTolerance: '30s' });

Nunca establezca una tolerancia superior a 2 minutos. Si necesita más, arregle su sincronización NTP.

Error #4: Orden de validación incorrecta

El orden de validación correcto es importante. Si verifica la firma después de verificar el vencimiento, un atacante puede crear un token con un exp futuro que pase la verificación de tiempo pero tenga una firma no válida.

Orden de validación segura:

  1. Encabezado de decodificación (verificar algoritmo)
  2. Verificar firma
  3. Verificar exp (rechazar si está vencido)
  4. Verificar nbf (rechazar si aún no es válido)
  5. Marcar iat (rechazar si es excesivamente antiguo)
  6. Verificar emisor, audiencia y otras afirmaciones

La mayoría de las bibliotecas bien mantenidas manejan esto correctamente, pero el middleware personalizado a menudo lo hace mal.

Error #5: Confusión de zona horaria en iat

Las marcas de tiempo

JWT son siempre UTC. Pero a veces los desarrolladores los crean usando la hora local:

// INCORRECTO — zona horaria local
const iat = nueva Fecha('2026-03-27T14:00:00').getTime() / 1000; // CORRECTO - UTC explícito
const iat = nueva Fecha('2026-03-27T14:00:00Z').getTime() / 1000;

Sin el sufijo Z, JavaScript interpreta la cadena en la zona horaria local, lo que puede cambiar la marca de tiempo en horas.

Error #6: Aceptar tokens sin nbf Check

La afirmación nbf es útil para tokens de activación retrasada; por ejemplo, un token que solo debería funcionar después de una implementación programada. Si su validador ignora nbf, estos tokens se pueden usar antes del tiempo de activación previsto.

La mayoría de las bibliotecas validan nbf de forma predeterminada, pero verifique esto en su configuración, especialmente con middleware personalizado.

Error nº 7: Caducidad demasiado larga

Establecer exp en 30 días para un token de acceso anula el propósito de los tokens de corta duración. Mejores prácticas:

Para patrones de token de actualización seguros, consulte nuestra guía sobre Rotación de token de actualización JWT.

Casos de prueba que toda API debería tener

Agregue estos a su conjunto de pruebas para detectar errores de reclamación de tiempo con anticipación:

  1. Token con exp en el pasado → 401
  2. Token con exp exactamente ahora → 401 (límite)
  3. Token sin exp → 401
  4. Token con nbf en el futuro → 401
  5. Token con nbf ligeramente en el futuro (dentro de la tolerancia) → 200
  6. Token con iat en el futuro → 401 (indica manipulación)
  7. Token con marcas de tiempo de milisegundos → 401 (detecta el error ms/s)

Valores predeterminados seguros para marcos populares

Node.js (jsonwebtoken)

jwt.sign(carga útil, secreto, { expiresIn: '15m' });
jwt.verify(token, secreto, { clockTolerance: 30, maxAge: '15m'
});

Python (PyJWT)

jwt.decode(token, clave, algoritmos=['HS256'], margen = timedelta (segundos = 30), opciones={'require': ['exp', 'iat']})

Go (golang-jwt)

parser := jwt.NewParser( jwt.WithLeeway(30 * tiempo.Segundo), jwt.WithValidMethods([]string{"HS256"}),
)

Preguntas frecuentes

¿Debería ser obligatorio?

Si bien la especificación JWT dice que iat es opcional, hacerlo obligatorio ayuda con la depuración y los registros de auditoría. Sin iat, no se puede determinar cuándo se creó un token, lo que dificulta la correlación con los eventos de seguridad.

¿Cuánta desviación horaria debo permitir?

Un valor predeterminado seguro común es de 30 a 60 segundos. Más de 2 minutos introduce un riesgo de seguridad. Si sus sistemas necesitan más, corrija la sincronización NTP en lugar de ampliar el margen de sesgo.

¿Qué código de estado HTTP debo devolver para un token caducado?

Devuelve 401 No autorizado con un cuerpo de error claro como {"error": "token_expired"}. No devuelva 403 Prohibido: eso implica que el token es válido pero carece de permisos, lo cual es una situación diferente.

Herramientas y artículos relacionados