pressione ⌘K para trocar de ferramenta
SECURITY

Decodificador de Tokens JWT

Decodifica JSON Web Tokens e visualiza seu conteúdo.

local
jwt-decoder

Decoding only — the signature is not verified. Nothing is sent anywhere.

§01 SOBRE ESTA FERRAMENTA

Visão geral

Um JWT são três partes codificadas em base64url e separadas por pontos: um cabeçalho que diz como ele foi assinado, um payload de claims e uma assinatura sobre as duas primeiras. A codificação não é criptografia. Quem tiver o token consegue ler todos os claims dentro dele, e vale internalizar isso antes de colocar qualquer coisa em um payload.

Esta ferramenta decodifica as duas primeiras partes e as formata, depois extrai os três claims de tempo e os converte de segundos Unix em datas que você consegue ler. Ela não verifica a assinatura — veja abaixo por que essa é a decisão correta e não uma funcionalidade faltando.

Como usar

  1. Cole o token. Tudo o que vem depois de Bearer — o esquema em si não faz parte do JWT.
  2. Leia o cabeçalho para ver o algoritmo e, se estiver presente, o id da chave.
  3. Leia o payload para ver os claims.
  4. Confira a tabela de datas para iat, nbf, exp e o veredicto de expiração.

Os claims registrados

ClaimNomeObservações
issEmissorQuem emitiu o token. Seu servidor deveria conferir isso contra uma lista de permissões
subSujeitoSobre quem o token é. Normalmente um id de usuário estável, não um e-mail
audAudiênciaPara quem o token foi emitido. Um token emitido para outra audiência tem de ser rejeitado
expExpiraçãoSegundos Unix. Depois disso, rejeite
nbfNão antes deSegundos Unix. Antes disso, rejeite
iatEmitido emSegundos Unix. Útil para «reautenticar se for mais antigo que N»
jtiID do JWTId único, para que um token possa ser revogado ou checado contra replay

Todos os sete são opcionais na especificação. Um token que omite exp nunca expira por conta própria, o que é uma decisão de projeto digna de nota quando você a encontra.

Por que a verificação de assinatura não é oferecida

Verificar uma assinatura exige a chave: o segredo compartilhado no caso do HS256, ou a chave pública no caso de RS256 e ES256. No caso simétrico, a chave que verifica é também a chave que assina — então uma página que oferecesse verificação estaria pedindo que você colasse a credencial que permite a qualquer um emitir tokens para o seu sistema. Não existe versão disso que seja segura de construir.

Decodificar continua valendo a pena. A maior parte da depuração de JWT é «o que este token diz, afinal» — audiência errada, escopo faltando, um exp cinco minutos no passado, um sub que é um e-mail quando o seu código espera um UUID. Tudo isso fica visível sem a chave.

O que decodificar não pode dizer é se o token é autêntico. Um JWT que você recebeu é uma alegação, não um fato, até que o seu servidor confira a assinatura contra uma chave em que confia.

O campo alg não é uma decisão que o seu verificador deva delegar

O alg do cabeçalho descreve o que o remetente usou. Um verificador que lê o alg e escolhe o algoritmo de acordo está confiando em uma entrada controlada pelo atacante, o que produz duas quebras clássicas:

  • alg: none. O JWT não protegido é legal na especificação. Um verificador que o honre aceita qualquer payload com assinatura vazia.
  • RS256 trocado por HS256. Se uma biblioteca pega a chave pública e a usa como segredo de HMAC, um atacante que conheça a sua chave pública — ela é pública — consegue assinar tokens que você vai aceitar.

Os dois são problemas de configuração, não de criptografia. Fixe o algoritmo esperado no seu verificador e rejeite qualquer outro, em vez de lê-lo do token.

Exemplos

  • Um 401 que você não consegue explicar. Decodifique e confira o aud. Um token emitido para uma API e apresentado a outra é a causa mais comum, e a mensagem de erro raramente diz isso.
  • Um 401 intermitente. Compare exp com iat. Um tempo de vida curto mais um cliente que guarda o token em cache é intermitente por construção.
  • Uma permissão que deveria funcionar. Procure scope ou roles no payload. Se o claim estiver ausente, o problema está no emissor, não no seu código de autorização.
  • Auditar o que você coloca em um token. Decodifique um dos seus. Tudo o que estiver ali — endereço de e-mail, ids internos, feature flags — é legível por quem tiver o token, inclusive pelo navegador onde ele está guardado.

Onde um token deve morar em um navegador

Isso aparece toda vez que alguém decodifica um token e nota que ele é legível. A versão curta: como um JWT é uma credencial ao portador, qualquer coisa que consiga lê-lo consegue usá-lo.

O localStorage é legível por qualquer script na origem, o que significa que um XSS leva o token com ele. Ele também nunca é enviado automaticamente, então você não pode sofrer CSRF por meio dele — você troca uma classe de bug por outra.

Um cookie HttpOnly não pode ser lido por script nenhum, então um XSS não consegue roubá-lo. Ele é enviado automaticamente, então precisa de SameSite=Lax ou Strict mais Secure, e todo endpoint que altera estado precisa da própria defesa contra CSRF.

A conclusão usual para uma aplicação de navegador é um access token de vida curta mantido apenas em memória, renovado a partir de um cookie de refresh token HttpOnly, Secure e com SameSite. Assim um XSS consegue um token com minutos de vida em vez de uma credencial que dura semanas, e o segredo de vida longa nunca fica alcançável pelo JavaScript.

Qualquer que seja a sua escolha, é o exp que faz o trabalho de verdade. Um token com uma hora de vida e sem lista de revogação é válido por uma hora depois de ser roubado, e nada do lado do cliente muda isso.

Observações

O padding é acrescentado antes da decodificação, porque base64url normalmente o omite. Tokens copiados de logs às vezes chegam com o padding intacto, e as duas formas funcionam aqui.

O veredicto de expiração usa o seu relógio local, então é uma conveniência e não uma autoridade. Se você precisa comparar com um instante específico, use o conversor de Unix time no valor bruto de exp.

Payloads não são sempre JSON em princípio — a especificação permite qualquer tipo de conteúdo — mas todo JWT na prática carrega um objeto JSON, e um payload que não consegue ser interpretado como JSON é exibido como texto bruto em vez de escondido.

FAQ
Isto verifica a assinatura?
Não, e isso é deliberado. Verificar exige a chave de assinatura, e colar uma chave de assinatura em uma página web é exatamente o erro que esta ferramenta não deve incentivar. Decodificar diz o que um token afirma; só o seu servidor pode dizer se a afirmação é verdadeira.
Meu token é enviado para algum lugar?
Não. O token é dividido nos pontos e decodificado em base64url dentro da própria página. Não existe requisição de rede. Ainda assim, trate como gasto qualquer token que você cole em algum lugar: um bearer token no histórico da sua área de transferência ou na sessão do navegador é uma credencial que você já não controla por completo.
Por que aparece EXPIRADO se minha API ainda aceita o token?
O status compara exp com o relógio do seu computador. Se o relógio estiver adiantado ou atrasado, ou se o emissor tolerar desvio de relógio (alguns minutos é comum), os dois veredictos podem discordar. O valor de exp do próprio token é o número que vale; o rótulo é uma conveniência.
Posso decodificar um token com apenas duas partes?
Sim. Duas partes é um JWT não protegido válido (alg igual a none) ou um token que você colou sem a assinatura. A ferramenta precisa do cabeçalho e do payload; a assinatura não é usada.
O payload parece um amontoado de lixo. O que aconteceu?
Na maioria das vezes o token está criptografado em vez de assinado (um JWE, que tem cinco partes) ou algo o recodificou — uma cópia de um terminal que quebrou a linha, ou de uma string JSON que o escapou. O payload de um JWS é base64url puro e sempre decodifica para JSON.