Mensagem de erro
token has invalid claims: token is expired
Também aparece como
- Token is expired
- token has invalid claims: token is not valid yet
- token has invalid claims: token used before issued
O golang-jwt v4 imprime “Token is expired” (com T maiúsculo). Os outros erros de claims da v5 usam o mesmo prefixo “token has invalid claims:”.
golang-jwt/jwt (Go) — jwt.ErrTokenInvalidClaims joined with jwt.ErrTokenExpired
O que significa
A assinatura do token foi verificada, mas a claim `exp` dele está no passado (além de qualquer tolerância que você tenha configurado). O golang-jwt v5 informa isso como `ErrTokenInvalidClaims` combinado com `ErrTokenExpired`; a mesma família gera “token is not valid yet” para um `nbf` no futuro e “token used before issued” para um `iat` no futuro. O token analisado ainda é retornado junto com o erro, mas não se deve confiar nele.
Por que acontece
O token passou do tempo de vida
comumTokens de acesso costumam durar de 5 a 60 minutos. Clientes que guardam um token em cache, repetem uma requisição muito depois ou o mantêm em um job de longa duração apresentam esse token depois do `exp`.
O relógio do verificador está adiantado
comumUm servidor com o relógio adiantado faz todos os tokens expirarem antes da hora. Contêineres herdam o relógio do host, então um único host sem NTP afeta todos os serviços dele.
O cliente não tem como renovar o token
ocasionalAplicações de página única e CLIs que guardam um token de acesso, mas nunca usam o token de atualização (ou nunca tratam o 401), falham para sempre assim que o primeiro token expira.
O exp foi escrito na unidade errada
raraO `exp` é dado em segundos desde a época Unix. Um emissor que divide os milissegundos duas vezes ou usa uma conversão de horário local pode gerar tokens que já nascem expirados.
Como corrigir
- 1.
Detectar a expiração e deixar o cliente renovar o token
Mapeie `ErrTokenExpired` para 401 com a indicação `invalid_token`. O cliente então usa o token de atualização (ou se autentica de novo) e tenta outra vez.
go token, err := jwt.Parse(raw, keyfunc, jwt.WithValidMethods([]string{"ES256"})) if errors.Is(err, jwt.ErrTokenExpired) { w.Header().Set("WWW-Authenticate", `Bearer error="invalid_token", error_description="token expired"`) http.Error(w, "token expired", http.StatusUnauthorized) // client refreshes and retries return } - 2.
Tolerar uma pequena diferença de relógio e exigir o exp
Uma tolerância de alguns segundos absorve a diferença entre os relógios das máquinas. `WithExpirationRequired` fecha a brecha oposta: sem ele, tokens sem `exp` nunca expirariam.
go parser := jwt.NewParser( jwt.WithValidMethods([]string{"ES256"}), jwt.WithLeeway(30*time.Second), // absorbs clock skew for exp, nbf and iat jwt.WithExpirationRequired(), // tokens without exp are rejected too )