Mensaje de error
jwt expired
Qué significa
TokenExpiredError de jsonwebtoken: el claim (declaración) exp del token (una marca de tiempo Unix en segundos) es anterior a la hora actual del reloj del verificador. La firma en sí puede ser perfectamente válida: simplemente, el token ha superado la vida útil que le dio el emisor. El objeto de error incluye expiredAt con el momento exacto.
Por qué ocurre
El token caducó de verdad
frecuenteLos tokens de acceso de corta duración (5–60 minutos) son lo habitual; un cliente que guarda un token en caché y lo reutiliza más tarde, o una tarea en segundo plano que conserva un token durante una ejecución larga, se topará con este error justo cuando toca. La solución es un flujo de actualización, no una vida útil más larga.
Desfase de reloj entre el emisor y el verificador
frecuenteSi el reloj del servidor que verifica va adelantado respecto al del emisor, los tokens «caducan» antes de tiempo, a veces en el mismo momento en que se emiten. Los contenedores y las VM sin NTP se desvían sorprendentemente rápido; un desfase de 2 minutos basta para romper de forma intermitente los tokens que duran menos de una hora.
exp escrito en la unidad incorrecta
ocasionalLa especificación (RFC 7519) define exp en segundos. El código que divide entre 1000 una vez de más produce marcas de tiempo de 1970, con lo que todos los tokens caducan al instante. El despiste contrario —escribir Date.now() (milisegundos) en exp— no provoca este error en absoluto: produce marcas de tiempo a más de 56.000 años en el futuro, y el token nunca caduca.
Cómo solucionarlo
- 1.
Permitir explícitamente un desfase pequeño
clockTolerance acepta segundos y se aplica a exp y nbf. Mantenla baja (30–60 s): sirve para absorber la deriva del reloj, no para alargar la vida útil de los tokens.
js jwt.verify(token, publicKey, { algorithms: ["ES256"], clockTolerance: 30, // seconds of tolerated skew }); - 2.
Inspeccionar exp antes de culpar al reloj
Decodifica los claims e imprime exp junto a tu hora actual. Si exp se parece a 1.7e12, tienes un error de milisegundos; si está unos minutos en el pasado, necesitas lógica de actualización.
js const { exp } = jwt.decode(token); console.log("exp:", new Date(exp * 1000).toISOString()); console.log("now:", new Date().toISOString()); - 3.
Sincronizar los relojes y añadir una vía de actualización
Ejecuta NTP (chrony/systemd-timesyncd) en los hosts que verifican e implementa en el cliente la actualización del token ante respuestas 401. Nunca lleves ignoreExpiration: true a producción: convierte cada token filtrado en una credencial permanente.