JWT Tokens Explained: Structure, Security & Decoding
Understand JSON Web Tokens from the inside out. Learn the header, payload, and signature structure, common claims, signing algorithms, and security best practices.
O que é um JWT?
Um JSON Web Token (JWT, pronunciado "jot") é uma string compacta e segura para URL que representa claims entre duas partes. É a forma mais comum de lidar com autenticação e autorização em aplicações web modernas.
Quando você entra em uma aplicação web e o servidor devolve um token em vez de criar uma sessão no lado do servidor, há grandes chances de esse token ser um JWT. O navegador o envia em cada requisição seguinte, e o servidor verifica a assinatura sem consultar o banco de dados.
Onde os JWTs são usados
- Autenticação. Depois que o usuário faz login, o servidor emite um JWT. O cliente armazena e envia no cabeçalho
Authorizationem cada requisição. - Single Sign-On (SSO). JWTs permitem que o usuário se autentique uma vez e acesse vários serviços. Provedores de identidade como Auth0, Okta e Keycloak emitem JWTs que serviços downstream podem verificar de forma independente.
- Autorização de API. Microsserviços passam JWTs uns aos outros para provar que uma requisição foi feita em nome de um usuário autenticado com permissões específicas.
- Troca de informações. Como os JWTs são assinados, podem transportar dados confiáveis entre partes sem uma etapa adicional de verificação.
As três partes de um JWT
Todo JWT consiste em três partes codificadas em Base64URL separadas por pontos:
header.payload.signature
Aqui está um JWT real (encurtado para facilitar a leitura):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Vamos decodificar cada parte.
Parte 1: Cabeçalho
O cabeçalho descreve o tipo do token e o algoritmo de assinatura. Decodificado de Base64URL:
{ "alg": "HS256", "typ": "JWT" }
Parte 2: Payload (claims)
O payload contém as claims — os dados reais que o token carrega. Decodificado:
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
O payload é codificado em Base64URL, não criptografado. Qualquer pessoa com o token pode decodificar e ler o payload. Nunca coloque segredos, senhas ou dados pessoais sensíveis no payload de um JWT.
Parte 3: Assinatura
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Experimente você mesmo: cole qualquer JWT no nosso Decodificador de JWT para inspecionar as três partes na hora.
Claims comuns em JWT
| Claim | Nome completo | Descrição |
|---|---|---|
sub | Subject | Sobre quem é o token (em geral um ID de usuário) |
iss | Issuer | Quem emitiu o token |
aud | Audience | Destinatário pretendido |
exp | Expiration Time | Timestamp Unix após o qual o token é inválido |
iat | Issued At | Timestamp Unix em que o token foi criado |
nbf | Not Before | O token é inválido antes deste timestamp |
jti | JWT ID | Identificador único para evitar reutilização do token |
Algoritmos de assinatura comparados
| Algoritmo | Tipo | Chave | Melhor para |
|---|---|---|---|
HS256 | Simétrico (HMAC) | Um único segredo compartilhado | Configurações simples |
RS256 | Assimétrico (RSA) | Par de chaves privada/pública | Sistemas distribuídos, SSO |
ES256 | Assimétrico (ECDSA) | Par de chaves privada/pública | Igual ao RS256, com chaves menores |
Boas práticas de segurança
- Nunca armazene segredos no payload. Use JWE para tokens criptografados.
- Use tempos de expiração curtos. 5 a 15 minutos.
- Sempre use HTTPS.
- Valide todas as claims. Verifique
exp,iss,aud. - Não aceite
alg: none. - Use uma lista permitida de algoritmos.
- Armazene tokens com segurança. Cookies
HttpOnlyem vez delocalStorage.
Erros comuns com JWT
- Colocar o JWT na URL.
- Não validar a assinatura.
- Segredo fraco para HS256.
- Tokens que nunca expiram.
- Armazenar dados demais.
Fluxo de renovação de token
- O usuário faz login. O servidor devolve access token (curta duração) e refresh token (longa duração).
- O cliente envia o access token em cada requisição.
- O access token expira; a API retorna 401.
- O cliente envia o refresh token para
/refresh. - O servidor emite novos tokens (rotação do refresh token).
- O cliente tenta de novo com o novo access token.
// Simplified refresh flow (client-side)
const handleApiRequest = async (url, options) => {
let response = await fetch(url, {
...options,
headers: { ...options.headers, Authorization: `Bearer ${getAccessToken()}` },
});
if (response.status === 401) {
const refreshResponse = await fetch("/api/refresh", {
method: "POST",
body: JSON.stringify({ refresh_token: getRefreshToken() }),
});
if (refreshResponse.ok) {
const { access_token, refresh_token } = await refreshResponse.json();
saveTokens(access_token, refresh_token);
response = await fetch(url, {
...options,
headers: { ...options.headers, Authorization: `Bearer ${access_token}` },
});
} else { redirectToLogin(); }
}
return response;
};
JWTs versus sessões: quando usar cada um
| Aspecto | JWT | Sessões no servidor |
|---|---|---|
| Armazenamento de estado | Cliente (sem estado) | Servidor (armazenamento de sessão) |
| Escalabilidade | Fácil | Exige armazenamento compartilhado |
| Revogação | Difícil | Fácil |
| Tamanho do payload | Maior | Menor |
| Cross-domain | Funciona bem | Exige configuração de CORS |
| Microsserviços | Ideal | Cada serviço consulta o armazenamento |
| Simplicidade | Mais complexo | Mais simples |
Use JWTs para serviços distribuídos, apps mobile e consumidores de API de terceiros. Use sessões para revogação simples, apps monolíticos e a opção segura mais direta.
Experimente você mesmo: decodifique e inspecione qualquer JWT na hora com o nosso Decodificador de JWT — nenhum dado sai do seu navegador.