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

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:
- exp (Tiempo de vencimiento): el token NO DEBE aceptarse después de esta marca de tiempo
- iat (Emitido en): cuando se creó el token
- nbf (No antes): el token NO DEBE aceptarse antes de esta marca de tiempo
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:
- Arquitecturas de microservicios con relojes no sincronizados
- Funciones sin servidor donde los contenedores tienen deriva de reloj
- Aplicaciones móviles donde el reloj del dispositivo se configura manualmente
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:
- Encabezado de decodificación (verificar algoritmo)
- Verificar firma
- Verificar
exp(rechazar si está vencido) - Verificar
nbf(rechazar si aún no es válido) - Marcar
iat(rechazar si es excesivamente antiguo) - 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 tiempoJWT 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:
- Tokens de acceso: 5 a 15 minutos
- Actualizar tokens: 7 a 30 días (con rotación)
- Tokens de identificación: 1 hora
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:
- Token con
expen el pasado → 401 - Token con
expexactamente ahora → 401 (límite) - Token sin
exp→ 401 - Token con
nbfen el futuro → 401 - Token con
nbfligeramente en el futuro (dentro de la tolerancia) → 200 - Token con
iaten el futuro → 401 (indica manipulación) - 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
- JWT Decoder - inspeccionar los reclamos de tiempo en cualquier token
- Errores de seguridad de JWT: errores más amplios de JWT más allá de las afirmaciones de tiempo
- Refresh Token Rotation — patrón seguro para sesiones de larga duración
- 2FA Guía: agregue una segunda capa más allá de los tokens