Header Decodificado
{
"alg": "HS256",
"typ": "JWT"
}
Payload Decodificado
{
"sub": "1234567890",
"name": "John Doe",
"email": "john@example.com",
"role": "admin",
"iat": 1516239022,
"exp": 1735689600
}
Assinatura
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
A assinatura não pode ser decodificada. Não são dados codificados, mas a saída de uma operação HMAC-SHA256. Para verificá-la, você precisa da chave secreta usada ao emitir o token.
Estrutura JWT de Três Partes
Um JWT são três seções codificadas em Base64url unidas por pontos:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0
.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
A estrutura é definida pela RFC 7519 e RFC 7515. Cada seção tem um propósito diferente:
Header
O header específica o tipo de token é o algoritmo de assinatura. alg informa ao válidador qual algoritmo foi usado para calcular a assinatura. typ é sempre JWT para tokens padrão. Alguns tokens também incluem kid (key ID) para indicar qual chave específica foi usada; issó importa quando um servidor de autorização rotaciona as chaves.
Payload
O payload contém os claims: declarações sobre o sujeito e metadados adicionais. Os claims registrados padrão têm nomês curtos para manter os tokens compactos (sub, iss, exp). Claims personalizados podem ser qualquer coisa que sua aplicação precise, mas a especificação JWT recomenda usar um formato com namêspace para claims personalizados para evitar colisões (por exemplo, https://myapp.com/role).
Assinatura
A assinatura é calculada sobre base64url(header) + "." + base64url(payload) usando o algoritmo especificado no header. Para HS256 é HMAC-SHA256(secret, data). Para RS256, é RSA-SHA256(privateKey, data). O válidador recalcula a assinatura a partir do header e payload recebidos é a compara com o terceiro segmento. Se não corresponderem, o token foi adulterado.
Codificação Base64url
JWTs usam Base64url, uma variante segura para URL do Base64. Substitui + por - e / por _, e omite os caracteres de padding =. Issó torna tokens JWT seguros para incluir em parâmetros de query URL e cabeçalhos HTTP sem percent encoding.
Base64 padrão exigiria caracteres de padding = e poderia incluir + ou /, ambos com significado especial em URLs. Base64url evita todos estes usando apenas caracteres que não precisam de escaping em URLs.
Para decodificar manualmente o segmento do payload:
# O segmento do payload (parte do meio, entre os dois pontos)
PAYLOAD="eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0"
# Adicione padding e decodifique (macOS/Linux)
python3 -c "
import base64, json, sys
s = sys.argv[1]
pad = s + '=' * (4 - len(s) % 4)
decoded = base64.urlsafe_b64decode(pad)
print(json.dumps(json.loads(decoded), indent=2))
" "$PAYLOAD"
Claims Padrão Explicados
| Claim | Nome | Tipo | Descrição |
|---|---|---|---|
sub | Subject | string | Sobre quem é o token. Tipicamente um ID de usuário. |
iss | Issuer | string | Quem emitiu o token. Geralmente uma URL (https://auth.example.com). |
exp | Expiration | timêstamp | Timêstamp Unix. Token deve ser rejeitado após este horário. |
iat | Issued At | timêstamp | Timêstamp Unix. Quando o token foi criado. |
aud | Audience | string/array | Para quem é o token. A API deve verificar se está listada. |
nbf | Not Before | timêstamp | Timêstamp Unix. Token não deve ser aceito antes deste horário. |
jti | JWT ID | string | Um identificador único para este token. Usado para prevenir replay. |
Nem todos os claims são obrigatórios. exp e sub são os mais comumente usados. O claim aud é importante para serviços que compartilham um servidor de autorização. Sem ele, um token destinado ao serviço A poderia ser usado contra o serviço B.
Decodificar Não Significa Confiar
Esta é a coisa mais importante a entender sobre decodificadores JWT. Decodificar um token revela os claims dentro dele. Não diz se esses claims são verdadeiros ou se o token é legítimo.
Um atacante pode construir qualquer JWT manualmente. Sem verificação de assinatura, não há como distinguir um token genuíno de um forjado. Issó importa porque:
-
Ataque
alg: none. Algumas bibliotecas JWT antigas aceitavam tokens com"alg": "none"no header e sem assinatura, tratando-os como válidos. Nunca aceite tokens sem assinatura. -
Ataques de confusão de algoritmo. Se seu servidor usa RS256 (assimétrico), um atacante pode enviar um token com
"alg": "HS256"no header, usando sua chave pública como o segredo HMAC. Bibliotecas com verificação de algoritmo fraca o válidariam com sucesso. Sempre especifique o algoritmo esperado explicitamente. -
Tokens expirados. Decodificar revela o claim
exp, mas você ainda precisa verificar se o horário atual já o ultrapassou.
Em produção, sempre use uma biblioteca JWT bem mantida que lida com verificação, pinning de algoritmo e verificação de expiração. Nunca implemente verificação JWT você mêsmo.
Onde JWTs São Usados
OAuth 2.0 / OpenID Connect
Access tokens e ID tokens em fluxos OAuth são frequentemente JWTs. O ID token no OIDC é sempre um JWT. Access tokens podem ou não ser JWTs dependendo do servidor de autorização.
Autenticação de API
Um servidor emite um JWT quando um usuário faz login. O cliente o envia no cabeçalho Authorization: Bearer <token> com requisições subsequentes. O servidor verifica a assinatura e lê os claims para identificar o usuário e verificar permissões.
Dados de sessão sem estado
Algumas aplicações codificam o estado da sessão (ID de usuário, papel, preferências) no payload do JWT para evitar consulta ao banco de dados em cada requisição. A troca: tokens não podem ser revogados antes da expiração sem infraestrutura adicional (uma lista de negação ou expiração curta + refresh tokens).
Autenticação serviço a serviço
Microsserviços internos usam JWTs para autenticar chamadas entre si, frequentemente com tempos de expiração curtos (minutos em vez de horas).
Depurando Problemas com JWT
Quando uma requisição autenticada com JWT falha, um decodificador é a primeira ferramenta a usar:
- O token expirou? Verifique
expcontra o timêstamp Unix atual. - O audience está correto? Verifique
audcorresponde ao que seu serviço espera. - O issuer está correto? Verifique
isscorresponde à URL do seu servidor de autorização. - Claims personalizados estão presentes? Se sua aplicação espera um claim
roleoupermissions, verifique se estão no payload. - O algoritmo está correto? Verifique
algno header corresponde ao que seu código de verificação espera.
Falhas de assinatura exigem a chave secreta ou pública real para diagnosticar. Um decodificador não pode dizer por que uma assinatura está errada, apenas qual algoritmo foi supostamente usado para criá-la.