O que é realmente um JWT
Um JSON Web Token é uma string. É aí que está todo o truque. Em vez de entregar ao cliente um identificador de sessão e guardar a sessão no servidor, você entrega uma afirmação assinada — “este é o usuário 4821, estas são suas permissões, isto expira às 14:05” — e deixa que ele a carregue. Qualquer serviço que confie na chave de assinatura pode ler a afirmação e agir sem consultar um banco de dados.
Isso torna os JWT muito convenientes e um pouco perigosos, pelo mesmo motivo: os dados estão nas mãos do cliente. Um token que você emite pode ser lido por quem o tiver, não pode ser retirado antes de expirar e será aceito por qualquer coisa que confie na assinatura. Quase todos os problemas com JWT em produção vêm de esquecer um desses três fatos.
Um token parece três blocos ilegíveis separados por pontos:
eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleS0yIn0.eyJzdWIiOiI0ODIxIiwiZXhwIjoxNzY1MTExMTExfQ.3xS7_c9Nn-aQ
Ele não é criptografado. Os dois primeiros blocos são JSON simples em Base64url, um alfabeto
seguro para URLs que troca + e / por - e _ e
descarta o preenchimento final de =. Qualquer pessoa consegue transformá-los de volta
em JSON num segundo — que é exatamente o que faz um decodificador JWT.
As três partes e o papel de cada uma
Divida o token nos pontos e você tem o cabeçalho, o payload e a assinatura.
O cabeçalho
Pequeno e quase sempre sobre chaves. alg nomeia o algoritmo de assinatura,
typ costuma ser JWT, e kid é um id de chave que diz a quem
verifica qual chave pública buscar quando o emissor tem mais de uma. Se um token para de validar
de repente depois de uma rotação de chaves, kid é o primeiro lugar para olhar.
O payload
As claims: a afirmação que de fato está sendo feita. Algumas são registradas pela especificação
(iss, sub, aud, exp, nbf,
iat, jti) e o resto é o que o seu emissor decidiu acrescentar:
scope, roles, tenant_id, um endereço de e-mail, uma flag de
recurso.
A assinatura
Um MAC ou uma assinatura digital sobre as duas primeiras partes, exatamente como aparecem na string. Esse detalhe importa: a assinatura cobre os bytes codificados, então reserializar o JSON e recodificá-lo produz um token que já não valida, mesmo com os dados idênticos. Nunca reconstrua um token para “arrumá-lo”.
Como decodificar um token e o que olhar primeiro
Cole a string inteira num decodificador, pontos incluídos. Se você a copiou de uma requisição,
remova o prefixo Bearer — ou use uma ferramenta que o remova por você. Depois leia
nesta ordem:
- Decodificou? Se o decodificador diz que as partes não são JSON Base64url válido, o token chegou truncado ou corrompido. Um cookie que bateu num limite de tamanho e um cabeçalho quebrado em linhas se parecem com isso.
exp. A expiração explica a maioria dos “funcionava cinco minutos atrás”, e é a primeira coisa a descartar.audeiss. Um token emitido para outra audiência é um token perfeitamente válido que sua API faz bem em rejeitar.- As claims personalizadas. Só depois de as claims padrão conferirem vale
discutir se
scopecontém o que você esperava.
Decodifique localmente sempre que possível. Um token é uma credencial viva, então colá-lo num site qualquer é o mesmo tipo de erro que colar uma senha: qualquer ferramenta que valha a pena decodifica no navegador e não envia nada a lugar algum.
As claims que decidem se um token funciona
Cinco claims fazem quase todo o trabalho, e cada uma pode rejeitar uma requisição por conta própria.
exp— expiração, como timestamp Unix em segundos. Um valor em milissegundos aqui é um bug clássico: cai no ano 57000 e o token nunca expira. Um bom decodificador mostra a data real e há quanto tempo ela passou.nbf— not before. O token é inválido até esse momento. Pouco usado de propósito, às vezes definido por acidente numa máquina com o relógio adiantado.iat— emitido em. Útil para rejeitar tokens tecnicamente não expirados mas suspeitamente antigos, e para notar um problema de relógio quandoiatestá no futuro.aud— audiência, o destinatário pretendido. Uma API que pula essa verificação aceitará de bom grado um token que outro de seus serviços emitiu para si mesmo, e esse é um caminho real de escalada de privilégios entre microsserviços.iss— emissor. Fixe-o no emissor exato que você espera e busque chaves apenas no conjunto publicado por esse emissor.
jti é o caso à parte: um id único de token. Só significa algo se você o armazenar e
conferir, mas é o que torna possível revogar um único token.
Decodificar não é verificar
Este é o ponto que pega as pessoas. Decodificar lê o Base64url e mostra o JSON. Diz o que um token afirma. Não diz nada sobre se a afirmação é verdadeira.
Qualquer um pode escrever {"sub":"1","role":"admin"}, passar para Base64url, grudar
qualquer string no fim como assinatura e entregar a você. Vai decodificar perfeitamente em qualquer
decodificador, inclusive no nosso. O que impede que funcione é a etapa de verificação: recalcular a
assinatura com a chave do emissor e recusar o token se não bater. Essa etapa exige um segredo ou
uma chave pública, pertence ao seu servidor, e nenhuma ferramenta de navegador pode fazê-la por
você.
Então trate um decodificador como uma leitura, nunca como prova. “Decodifiquei e diz admin” não é um achado de segurança. “Meu servidor verificou e diz admin” é.
Por que um token de aparência válida recebe 401
Quando o token decodifica limpo e a API ainda o recusa, quase sempre é uma destas:
- Expirado. Confira
expcontra o relógio do servidor, não o seu. - Diferença de relógio. Um servidor dois minutos adiantado vai recusar tokens recém-emitidos. A maioria das bibliotecas permite uma pequena folga exatamente por isso; se a sua está em zero, vale rever.
- Audiência errada. Comum quando um provedor de identidade atende várias APIs.
- Rotação de chaves. O emissor assinou com uma chave nova, quem verifica ainda
tem o conjunto antigo em cache, e
kidjá não resolve. - O token nunca chegou. Um cabeçalho
Authorizationausente ou mal formado, um cookie perdido, ou um proxy removendo cabeçalhos. Veja o que o servidor realmente recebeu antes de culpar o token: a consulta de códigos de status HTTP e nosso guia de códigos de status ajudam a distinguir um 401 de um 403 que significa algo bem diferente.
401 ou 403?
Um 401 significa que a credencial está ausente, expirada ou não verificável:
conserte o token. Um 403 significa que a credencial estava boa e a resposta continua
não: conserte as permissões, ou a claim scope. Serviços que devolvem 401 para uma
falha de autorização mandam as pessoas depurar um token que nunca foi o problema.
Escolher e conferir o algoritmo de assinatura
Na prática importam duas famílias. HS256 é um HMAC com segredo compartilhado: quem pode verificar também pode assinar, o que serve dentro de um serviço e encaixa mal entre organizações. RS256 e ES256 usam uma chave privada para assinar e uma pública para verificar, então uma API pode validar tokens que jamais poderia ter emitido.
E há alg: none, um token sem assinatura que a especificação permite e que você
nunca deve aceitar. Ele existe no padrão, portanto existiu em bibliotecas, portanto foi explorado:
a quem verifica tomando o algoritmo do próprio cabeçalho do token é possível dizer “este não
está assinado, apenas confie”. Um truque parecido entrega a um verificador RS256 um token
HS256 assinado usando a chave pública como segredo HMAC.
A defesa é uma linha de política: decida quais algoritmos você aceita antes de olhar o
token e rejeite o resto. O cabeçalho é uma dica sobre qual chave usar, não uma instrução
sobre conferir ou não a assinatura. Se o seu decodificador marca alg: none em
vermelho, é por isso.
O que nunca deve ir num payload
Como o payload é codificado e não criptografado, cada claim é pública para quem tiver o token — e tokens acabam no armazenamento do navegador, em logs, em rastreadores de erro, em tickets de suporte e em capturas de tela. Mantenha fora do payload:
- Qualquer coisa que você não colocaria numa URL: senhas, chaves de API, números de cartão, dados de saúde.
- Identificadores internos que você prefere não publicar: chaves primárias de banco, nomes de host internos, condições de licença.
- Blocos grandes. Cada requisição carrega o token; um kilobyte de claims é um kilobyte em cada chamada, e tokens grandes demais são um jeito confiável de bater nos limites de tamanho de cabeçalho de um proxy.
Mantenha os tokens fora das URLs também. Um token numa query string vai para os logs do
servidor, para cabeçalhos Referer e para o histórico do navegador. Envie-o no
cabeçalho Authorization e garanta que seu site define um Referrer-Policy
sensato: nosso guia de cabeçalhos de
segurança cobre isso, e o verificador de
cabeçalhos de segurança dirá o que você está enviando hoje.
Expiração, refresh e o problema da revogação
Um JWT não pode ser chamado de volta. Uma vez emitido, vale até exp, aconteça o que
acontecer com a conta por trás. Desative um usuário e o token de acesso dele continua funcionando
até acabar. Esse é o preço de não consultar um banco de dados em cada requisição.
A resposta padrão são dois tokens. Um token de acesso de vida curta — minutos, não dias — carrega as claims e faz o trabalho. Um token de refresh de vida longa fica no servidor, é conferido contra um banco a cada uso e pode ser revogado na hora. Desconectar alguém passa a ser invalidar o token de refresh e esperar a janela curta até o token de acesso morrer sozinho.
Escolha a janela de expiração de propósito: ela é o intervalo entre revogar o acesso e o acesso
de fato parar. Quinze minutos é um meio-termo comum. Horas são difíceis de justificar; dias
significam que você não tem revogação alguma. E se precisar de revogação imediata, mantenha uma
lista de negação de valores jti — e aí você volta a consultar um armazenamento em cada
requisição, e uma sessão comum pode ser o desenho mais simples.
Qualquer que seja a escolha, o ciclo de depuração é o mesmo: decodifique o token, leia
exp e aud, confirme o relógio e então verifique a assinatura no servidor.
Quatro passos, nessa ordem, e quase todo problema de token aparece nos dois primeiros.
Ferramentas e guias relacionados:
- Decodificador JWT — Decodifique um JSON Web Token e leia o cabeçalho, o payload, as claims e a expiração.
- Codificador e decodificador Base64 — Codifique texto para Base64 ou de volta, com saída URL-safe e UTF-8 tratado.
- Base64 explicado: como a codificação e a decodificação funcionam — Como o Base64 transforma bytes em texto
Perguntas frequentes
Posso decodificar um JWT sem a chave secreta?⌄
Sim. O cabeçalho e o payload são codificados em Base64url, não criptografados, então qualquer um que tenha o token pode lê-los. A chave só é necessária para verificar a assinatura. É também por isso que você nunca deve colocar dados sensíveis num payload.
É seguro colar um JWT num decodificador online?⌄
Só se a decodificação acontecer no seu navegador. Um token é uma credencial viva até expirar, então uma ferramenta que o envia para um servidor está manuseando sua credencial. Nosso decodificador roda inteiramente na página e não envia o token a lugar algum, mas o hábito mais seguro é usar tokens expirados ou de teste sempre que possível.
Por que meu token decodifica bem e ainda assim retorna 401?⌄
Decodificar prova apenas que a string está bem formada. Os culpados usuais são um exp já passado, uma diferença de relógio entre emissor e verificador, um aud que nomeia outra API, ou um kid que o verificador não consegue resolver depois de uma rotação de chaves.
Qual a diferença entre JWT e um cookie de sessão?⌄
Um cookie de sessão é um ponteiro: o servidor guarda o estado e o consulta em cada requisição, então pode ser revogado na hora. Um JWT carrega o próprio estado, então nenhuma consulta é necessária — e nada pode ser retirado antes de expirar. JWT escala melhor entre serviços; sessões dão controle a você.
Devo usar HS256 ou RS256?⌄
HS256 compartilha um segredo, então quem pode verificar também pode assinar. Isso é aceitável dentro de um único serviço. RS256 e ES256 assinam com chave privada e verificam com pública, que é o que você quer assim que há mais de uma parte envolvida. De qualquer forma, fixe os algoritmos aceitos no seu verificador e nunca confie no valor alg do token.
Mais de 15 anos de experiência prática em desenvolvimento web e segurança. Foco em segurança web prática: manter sites seguros, confiáveis e fáceis de diagnosticar. O BuildToolForge existe para tornar essas verificações gratuitas, privadas e compreensíveis. As ferramentas rodam no seu navegador sempre que possível, e nada do que você digita em uma ferramenta é armazenado.
Como escrevemos nossos guias: Cada guia nasce da experiência prática, é conferido com os padrões oficiais e testado com nossas próprias ferramentas em domínios reais. Atualizamos os guias quando padrões ou ferramentas mudam. Encontrou um erro? Escreva para contact@buildtoolforge.com.