Como saber se um token JWT expirou (claim exp)

Por • 31 Outubro, 2026 • Segurança • 12 minutos de leitura

Veja se um JWT expirou: leia o claim exp, confira no seu fuso horário e evite as armadilhas de milissegundos, leeway e base64url. Decodificador grátis.

Um token JWT expirou quando o horário atual é igual ou posterior à claim exp. O valor de exp é um número de segundos contados desde 1º de janeiro de 1970, em UTC: 1793372400 é 30 de outubro de 2026 às 15:00:00 UTC, ou 12:00 em Brasília. Para conferir, decodifique a parte do meio do token, leia o exp e compare com o relógio. O nosso decodificador de JWT grátis faz isso para você. Cole o token e ele mostra Expirado ou Não expirou, além da data exata no seu fuso horário e em UTC.

É grátis, não precisa de conta e roda inteiro no seu navegador. No nosso teste de 31 de outubro de 2026, a página não enviou nenhuma requisição contendo o token. Visitantes têm 5 usos de ferramentas por dia, e uma conta gratuita do My Botsy (100% grátis, sem spam) remove esse limite diário. Todos os resultados citados são reais. Os do decodificador vêm de testes no mybotsy.com em 31 de outubro de 2026. Os das bibliotecas vêm de PyJWT 2.15.1, jsonwebtoken 9.0.3 e jose 6.2.14, rodadas no mesmo dia.

O que significa a claim exp

O RFC 7519, padrão do JWT, define três claims de tempo. As três são opcionais e todas usam o tipo NumericDate, ou seja, segundos, e não milissegundos:

  • exp (expiration time): a partir desse instante, inclusive, o token não deve ser aceito.
  • nbf (not before): antes desse instante, o token também não deve ser aceito.
  • iat (issued at): quando o token foi emitido. Sozinho, não invalida nada, mas serve para calcular a idade do token.

Para exp e nbf, o RFC permite uma pequena folga, «normalmente não mais que alguns minutos», para compensar a diferença entre relógios. É por causa dessa folga que dois sistemas podem discordar sobre um token que expirou há poucos segundos.

Como verificar se o token JWT expirou, passo a passo

  1. Copie o token. É aquela string longa com dois pontos que aparece depois de Authorization: Bearer no cabeçalho da requisição, ou que fica salva num cookie ou no localStorage.
  2. Cole no decodificador de JWT. Não precisa limpar antes: a ferramenta tira Authorization:, Bearer, aspas, espaços e quebras de linha, e avisa que fez isso.
  3. Veja a linha Status. Ela mostra Expirado, Não expirou, Ainda não é válido (quando o nbf está no futuro), Sem expiração (sem exp) ou Expiração ilegível: exp não é um número válido (quando o exp existe mas não é um número).
  4. Confira a linha Expira em (exp). Ela traz a data no seu fuso, o mesmo instante em UTC, um tempo relativo («ontem», «em 2 meses») e o número original.
  5. Olhe a Duração. É o exp menos o iat. Se um token de acesso dura 30 dias, o problema está em como os tokens são emitidos, e não nesse token.
  6. Leia os avisos. O decodificador alerta para datas em milissegundos, para alg: none e para tokens com preenchimento. Ele também lembra que não verifica a assinatura.

Exemplos resolvidos (saída real do decodificador)

Assinamos estes tokens de teste com HS256 e um segredo de demonstração descartável. Depois colamos cada um em mybotsy.com/pt/jwt-decoder em 31 de outubro de 2026, por volta das 15:07 UTC, com o navegador no horário de São Paulo.

Exemplo 1: um token expirado

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzg4NDEiLCJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJhdWQiOiJvcmRlcnMtYXBpIiwiaWF0IjoxNzkzMzY4ODAwLCJleHAiOjE3OTMzNzI0MDB9.FJV2oXvW0F-Q7x6rzZRKosQG_DhxLQXXz87wW-Ctq60
LinhaSaída do decodificador
StatusExpirado
Emitido em (iat)sexta-feira, 30 de outubro de 2026 às 11:00:00 BRT · 2026-10-30T14:00:00Z · ontem · 1793368800
Expira em (exp)sexta-feira, 30 de outubro de 2026 às 12:00:00 BRT · 2026-10-30T15:00:00Z · ontem · 1793372400
Duração1 hora

As três bibliotecas concordaram. O PyJWT lançou ExpiredSignatureError: Signature has expired, o jsonwebtoken lançou TokenExpiredError: jwt expired com expiredAt 2026-10-30T15:00:00.000Z e o jose retornou ERR_JWT_EXPIRED.

Exemplo 2: um token válido colado com o cabeçalho

Colamos a linha inteira, Authorization: Bearer eyJhbGciOiJIUzI1NiIs…. O decodificador avisou «O texto foi limpo antes da decodificação» e mostrou Não expirou, com exp em quinta-feira, 31 de dezembro de 2026 às 21:00:00 BRT, ou seja, 2027-01-01T00:00:00Z («em 2 meses»), e Duração de 61 dias 9 horas. Repare na data: um token que expira à meia-noite UTC do Ano-Novo para de funcionar no Brasil às 21h do dia 31. Olhar só o número, ou só a data local, é o jeito mais comum de errar o dia.

Exemplo 3: ainda não é válido

Um token com nbf 1796083200 e exp 1796169600 deu Ainda não é válido, com Válido a partir de segunda-feira, 30 de novembro de 2026 às 21:00:00 BRT (2026-12-01T00:00:00Z). O PyJWT retornou ImmatureSignatureError e o jsonwebtoken, NotBeforeError: jwt not active. Se um token recém-emitido for recusado, confira o nbf e o relógio do servidor antes de culpar a expiração.

Exemplo 4: sem exp

O payload {"sub":"svc-reporting","iat":1790856000} deu Sem expiração (sem exp), e as três bibliotecas o aceitaram. Se um token assim vazar, ele continua funcionando até a chave ser trocada. No PyJWT, com options={"require": ["exp"]}, o mesmo token passou a dar MissingRequiredClaimError: Token is missing the "exp" claim.

Armadilhas que dão a resposta errada

exp em milissegundos

O erro clássico é gravar Date.now() direto no exp. Assinamos um token com "exp":1793462400000. O decodificador avisou «O valor de exp parece estar em milissegundos» leu o valor como milissegundos e mostrou a data real, 31 de outubro de 2026 às 16:00 UTC, com o status e a duração corretos. O jsonwebtoken e o jose aceitaram o token, ou seja, na prática ele nunca expira. O PyJWT recusou, mas pela checagem do iat («The token is not yet valid (iat)»), não pelo exp. A correção: divida por 1000 ao emitir o token e multiplique por 1000 ao montar um Date do JavaScript a partir do exp.

exp como texto

"exp":"1798761600", entre aspas, quebra o padrão. O jsonwebtoken recusou com invalid exp value, e o jose com "exp" claim must be a number. Já o PyJWT aceitou e ainda aplicou a regra: com uma data vencida em texto, lançou ExpiredSignatureError. Resultado: o mesmo token passa num serviço e falha em outro. O decodificador mostra «Não é uma data válida: deve ser um número de segundos» ao lado do valor, um aviso, e a linha Status diz Expiração ilegível: exp não é um número válido.

Diferença de relógio e folga (leeway)

Criamos um token que tinha expirado 20 segundos antes. Sem folga, as três bibliotecas o recusaram. Com 30 segundos (leeway=30 no PyJWT, clockTolerance: 30 no jsonwebtoken e no jose), as três aceitaram. Mantenha a folga pequena, porque cada segundo a mais estende a vida de todos os tokens, inclusive dos roubados.

Decodificar com base64 --decode

O JWT usa base64url, que troca + e / por - e _. O comando famoso cut -d. -f2 | base64 --decode | jq .exp funciona até o payload ter um desses caracteres. No GNU coreutils 9.7, um payload com - imprimiu metade do JSON e depois base64: invalid input, e o jq falhou com Unfinished string. Troque os caracteres antes com tr '_-' '/+', ou cole o token no decodificador, que lê base64url nativamente. Para outros problemas com Base64, veja como decodificar Base64.

Decodificar não é verificar

Qualquer pessoa pode montar um token com exp no ano 2100. Ler o exp serve para depurar ou para o navegador decidir quando renovar o token. Antes de confiar numa requisição, o servidor precisa verificar a assinatura com uma lista fixa de algoritmos permitidos. O RFC 8725 descreve ataques em que o algoritmo foi trocado para none, e o nosso decodificador mostra um alerta vermelho quando encontra alg: none.

Verificar a expiração no código

Estas funções servem para exibir a data ou agendar a renovação, não para segurança. Testamos as duas com os tokens acima. O expirado retornou true, o válido e o de base64url retornaram false, e os tokens sem exp ou com exp em texto não retornaram data.

// JavaScript (navegador ou Node 16+)
function jwtExpiry(token) {
  const part = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
  const { exp } = JSON.parse(atob(part));
  if (typeof exp !== 'number') return null;   // sem exp, ou exp em texto
  return new Date(exp * 1000);                 // segundos -> ms
}
function isExpired(token, leewaySeconds = 0) {
  const exp = jwtExpiry(token);
  return exp !== null && Date.now() >= exp.getTime() + leewaySeconds * 1000;
}
# Python 3
import base64, json, time

def jwt_exp(token):
    seg = token.split(".")[1]
    seg += "=" * (-len(seg) % 4)   # repõe o preenchimento que o JWT remove
    exp = json.loads(base64.urlsafe_b64decode(seg)).get("exp")
    return exp if isinstance(exp, (int, float)) else None

def is_expired(token, leeway=0):
    exp = jwt_exp(token)
    return exp is not None and time.time() >= exp + leeway

A comparação é «maior ou igual» porque, pelo RFC, o token deixa de valer no instante do exp. No servidor, use a função de verificação da sua biblioteca (jwt.decode com chave no PyJWT, jwt.verify no jsonwebtoken, jwtVerify no jose), que confere a assinatura e as datas juntas.

Boas práticas de segurança

  • Trate um token válido como uma senha. Até expirar, quem estiver com ele pode agir como aquele usuário. Prefira um decodificador local como o nosso a colar tokens em chats ou chamados.
  • Use tokens de acesso de vida curta e exija exp no servidor.
  • Use um segredo HS256 longo e aleatório. O PyJWT avisou que a nossa chave de teste de 20 bytes estava «below the minimum recommended length of 32 bytes for SHA256». Um segredo de 64 caracteres do gerador de senhas passa com folga desse mínimo. O nosso guia para criar uma senha forte explica por que o tamanho importa.
  • Nada secreto vai no payload. Ele é só codificado, e qualquer pessoa consegue lê-lo com um decodificador Base64. Se o payload decodificado não abrir como JSON, passe-o no validador de JSON e veja como corrigir um JSON inválido.

Certificados também expiram. Se o erro de «expirado» vier do HTTPS e não de um token, veja como verificar a data de validade de um certificado SSL.

Confira o seu token agora

Cole o token no decodificador de JWT grátis. É grátis e não precisa de conta. O token fica no seu navegador, e você vê o status, todas as datas no seu fuso e em UTC, e alertas para cada armadilha acima.

Perguntas frequentes

Como sei quando o meu JWT expira?

Decodifique o payload e leia a claim exp, que conta os segundos desde 1º de janeiro de 1970 em UTC. Multiplique por 1000 para ter uma data no JavaScript, ou cole o token no decodificador de JWT do My Botsy, que mostra o exp no seu fuso horário e em UTC.

Um JWT expira exatamente no horário do exp?

Sim. O RFC 7519 diz que o token não deve ser aceito a partir do horário do exp, inclusive, então compare com maior ou igual. Muitos servidores somam alguns segundos de folga por causa da diferença de relógio.

Por que o servidor recusa um token que o decodificador diz que não expirou?

As causas comuns são o relógio do servidor diferente, um nbf no futuro, audiência ou emissor errados, ou uma assinatura inválida. O decodificador só lê as datas. O servidor confere também a assinatura e as outras claims.

E se o JWT não tiver exp?

A maioria das bibliotecas aceita, e o token nunca expira sozinho. Exija o exp no servidor (por exemplo, com a opção require do PyJWT) e use tokens de acesso de vida curta.

É seguro colar um JWT num decodificador online?

Só se o decodificador rodar localmente. O do My Botsy decodifica no seu navegador, e o token nunca é enviado ao nosso servidor. Mesmo assim, trate qualquer token válido como uma senha, e use tokens expirados ou de teste quando compartilhar exemplos.

O decodificador de JWT do My Botsy é grátis?

Sim. É grátis, não precisa de conta e roda no seu navegador. Visitantes têm 5 usos por dia, e uma conta gratuita remove esse limite.

Como saber onde uma foto foi tirada (localização GPS)

30 Outubro, 2026

Veja se uma foto revela onde foi tirada: leia os dados GPS no navegador, marque as coordenadas certas no mapa e remova a localização antes d..

Como saber se um site é confiável: 6 verificações grátis

29 Outubro, 2026

Saiba se um site é confiável antes de pagar: domínio real, idade no WHOIS, certificado SSL, redirecionamentos, hospedagem e Google Safe Brow..

Como criar uma senha forte que você consegue lembrar

28 Outubro, 2026

O que torna uma senha forte hoje, como montar uma frase-senha fácil de lembrar e como cuidar do resto com um gerenciador e 2FA.