Decodificando em um passo
Um JSON Web Token tem esta cara: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMifQ.assinatura, ou seja, três strings em Base64url unidas por pontos. Todo JWT começa com eyJ porque é assim que os caracteres {" ficam em Base64.
Cole o token na ferramenta abaixo. O prefixo Bearer copiado de um header Authorization é aceito. Você vê o header e o payload como JSON formatado, as claims exp, iat, nbf e auth_time como datas no seu horário local com uma indicação relativa, e uma linha de status que diz se o token expirou ou se ainda não é válido. Para conferir a assinatura, digite o segredo compartilhado ou a chave pública em Segredo ou chave pública (opcional).
Experimente aqui: Decodificador JWT
Abrir a página completa da ferramentaAs três partes de um JWT
- Header: um pequeno objeto JSON como {"alg":"HS256","typ":"JWT"}. alg indica o algoritmo de assinatura; kid, quando existe, identifica qual chave foi usada, o que ajuda quando o emissor faz rotação de chaves.
- Payload: as claims, isto é, afirmações sobre o usuário e o token, por exemplo o ID do usuário, o emissor, o público, os perfis de acesso e o horário de expiração. Qualquer pessoa que tenha o token consegue lê-las.
- Assinatura: calculada sobre o header e o payload codificados com um segredo (HMAC) ou uma chave privada (RSA ou curva elíptica). Ela prova que as duas primeiras partes não foram alteradas e que foram emitidas por quem tem a chave.
- Um token com cinco partes em vez de três é um JWE criptografado. O payload dele não pode ser lido sem a chave privada, e a ferramenta avisa quando você cola um.
Claims comuns e o que significam
O padrão JWT (RFC 7519) registra alguns nomes curtos de claims. Os horários são valores NumericDate: segundos desde 1º de janeiro de 1970 UTC, não milissegundos. Confundir os dois é um bug clássico, por exemplo comparar exp com o Date.now() do JavaScript, que devolve milissegundos.
| Claim | Nome | Significado |
|---|---|---|
| iss | Issuer (emissor) | Quem criou o token, muitas vezes a URL do provedor de identidade |
| sub | Subject (assunto) | Sobre quem é o token, normalmente um ID de usuário |
| aud | Audience (público) | Qual API ou aplicativo deve aceitá-lo |
| exp | Expiration time (expiração) | Depois deste momento o token deve ser recusado |
| nbf | Not before (não antes de) | Antes deste momento o token ainda não é válido |
| iat | Issued at (emitido em) | Quando o token foi criado |
| jti | JWT ID | ID único, usado para impedir reutilização ou revogar um token |
| auth_time | Authentication time (hora do login) | Quando o usuário realmente fez login (OpenID Connect) |
Decodificando na mão ou no código
O Base64url é diferente do Base64 padrão: usa hífen e sublinhado no lugar de + e /, e o preenchimento com = é removido. A maioria das falhas de decodificação vem de jogar uma parte do JWT direto num decodificador Base64 padrão. Troque o hífen por + e o sublinhado por /, acrescente = até o tamanho ser múltiplo de 4 e então decodifique.
Em Python, base64.urlsafe_b64decode(parte + "==") cuida do alfabeto, e o preenchimento a mais é tolerado. No console do navegador, atob funciona depois de trocar os dois caracteres, mas devolve os bytes como Latin 1, então nomes com acento no payload precisam de um TextDecoder para sair em UTF-8 correto. Bibliotecas como PyJWT, jsonwebtoken para Node.js ou System.IdentityModel.Tokens.Jwt para .NET decodificam e verificam numa única chamada; em produção use a função que verifica, não um atalho que só decodifica.
Para uma olhada rápida, uma ferramenta é mais prática e evita deixar o token no histórico do terminal.
Decodificar não é verificar
Ler o payload mostra o que o token afirma; não prova que as afirmações são verdadeiras. Qualquer um pode criar um token com "role": "admin" e codificar em Base64. Só uma assinatura válida, conferida com a chave certa, torna o conteúdo confiável. O servidor deve sempre verificar antes de usar qualquer claim.
Na ferramenta, tokens HS256, HS384 e HS512 são verificados com o segredo compartilhado. Tokens RS, PS e ES são verificados com a chave pública do emissor em formato PEM, o bloco que começa com BEGIN PUBLIC KEY. Se o seu provedor de identidade publica as chaves só como uma lista JWKS, converta antes para PEM a chave correspondente (aquela cujo kid bate com o do header). O resultado aparece como A assinatura é válida ou A assinatura não corresponde à chave. Se você colar uma chave privada, a ferramenta pede a pública no lugar dela.
Fique atento a estes sinais de alerta: alg definido como none (o token não tem assinatura nenhuma, e a ferramenta o marca como sem assinatura), um algoritmo inesperado (um servidor que espera RS256 nunca deve aceitar um token HS256, um ataque conhecido) e tokens cujo iss ou aud não batem com o seu sistema.
Resolvendo tokens expirados e inválidos
- Token expirado: confira a data de exp na seção Datas. Tokens de acesso muitas vezes vivem só de 5 a 60 minutos de propósito; o aplicativo deve usar um refresh token para obter um novo.
- Ainda não é válido: nbf ou iat está no futuro, o que normalmente quer dizer que o relógio do servidor e o do emissor estão diferentes. Muitas bibliotecas toleram uma pequena diferença de relógio, de alguns segundos a alguns minutos; acerte o relógio com sincronização de horário.
- Isto não parece um JWT: o token foi cortado, ficou entre aspas ou ganhou espaços ao ser copiado. Copie de novo do header ou do cookie original.
- Não foi possível ler o header ou o payload: falta uma parte do token. Tokens longos muitas vezes aparecem cortados nos logs.
- A assinatura não corresponde: segredo errado, chave pública de outro ambiente (homologação em vez de produção), chave que já foi trocada ou token que foi alterado.
Lide com tokens com segurança
Um token de acesso válido funciona como uma senha até expirar. Não cole tokens ativos de produção em sites que os enviam a um servidor, e não publique tokens em chamados ou no chat. Este decodificador roda inteiro no seu navegador: o token não é enviado, registrado nem guardado.
Do lado de quem emite, mantenha o payload pequeno e sem segredos. Como qualquer um pode ler, nunca coloque senhas, chaves de API ou dados pessoais que o cliente não deve ver dentro de um JWT. Guarde o ID do usuário e os perfis e busque todo o resto no servidor.