Mensagem de erro
"exp" claim timestamp check failed
jose (JavaScript) — JWTExpired, code ERR_JWT_EXPIRED
O que significa
A validação de claims do jose rejeitou o token porque o timestamp exp já passou em relação ao relógio do verificador. A verificação da assinatura já tinha sido aprovada — trata-se apenas de uma falha de prazo. O jose usa o mesmo padrão de texto para outras claims ("nbf" claim timestamp check failed) quando um token é usado antes do início da validade (not-before).
Por que acontece
O token passou do tempo de vida
comumTokens de acesso são feitos para durar pouco. Um cliente que guarda tokens em cache sem checar a expiração, um consumidor de fila que processa uma mensagem horas depois de ela ter sido enfileirada com um token dentro ou uma fixture de teste com um token fixo no código caem todos aqui de forma determinística.
Relógio do verificador adiantado em relação ao do emissor
comumAlguns minutos de desvio de relógio no host que faz a verificação encurtam o tempo de vida efetivo de todos os tokens e podem levar à rejeição de tokens recém-emitidos. Contêineres herdam o relógio do host — uma VM com o relógio desajustado quebra todos os pods dela de uma vez.
Unidade errada gravada em exp
ocasionalO exp precisa estar em segundos desde a época Unix (RFC 7519). Um código emissor que divide errado ou passa um objeto Date serializado em milissegundos gera tokens que já nascem expirados ou que valem por milênios.
Como corrigir
- 1.
Adicionar uma tolerância de relógio limitada
O jose aceita a opção clockTolerance (um número de segundos ou uma string legível por humanos). Mantenha-a pequena; ela serve para absorver o desvio de relógio, não para estender o tempo de vida.
js import { jwtVerify } from "jose"; await jwtVerify(token, key, { algorithms: ["ES256"], clockTolerance: "30s", }); - 2.
Imprimir a linha do tempo antes de mudar qualquer coisa
Compare iat, exp e o “agora” do verificador. O padrão revela a causa: exp poucos segundos no passado → problema de renovação do token; exp antes de iat → bug na emissão; exp ≈ agora, mas falhando → diferença de relógio.
js import { decodeJwt } from "jose"; const { iat, exp } = decodeJwt(token); console.log({ iat: new Date(iat * 1000), exp: new Date(exp * 1000), now: new Date() });