Dev Tools

JWT: Como Funciona, Como Decodificar e Erros Comuns

Entenda a estrutura do JSON Web Token, como funciona a autenticação com JWT, aprenda a decodificar tokens e evitar vulnerabilidades de segurança.

27 de fevereiro de 202610 min de leituraDevThru

O JWT (JSON Web Token) se tornou o padrão de autenticação mais usado em APIs modernas. Se você trabalha com backend, frontend ou mobile, entender como JWT funciona é essencial — e debugar tokens faz parte do dia a dia.

Neste guia, vamos destrinchar a estrutura de um JWT, explicar o fluxo de autenticação, mostrar como decodificar tokens e cobrir os erros de segurança mais comuns.

O Que É JWT?

JWT é um padrão aberto (RFC 7519) que define um formato compacto e seguro para transmitir informações entre partes como um objeto JSON. O token é assinado digitalmente, garantindo que seu conteúdo não foi adulterado.

Um JWT tem esta aparência:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik1hcmlhIiwiaWF0IjoxNjE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
💡 Importante: JWT é assinado, não criptografado. Qualquer pessoa pode decodificar o payload. Nunca coloque dados sensíveis (senhas, cartões de crédito) dentro de um JWT.

Estrutura do JWT: As 3 Partes

Um JWT é composto por três partes separadas por pontos (.):

ParteNomeConteúdo
HeaderAlgoritmo e tipo do token
PayloadClaims (dados do usuário/sessão)
SignatureAssinatura para verificação

1. Header

Indica o algoritmo de assinatura e o tipo do token:

{
  "alg": "HS256",
  "typ": "JWT"
}

Os algoritmos mais comuns são:

  • HS256 — HMAC com SHA-256 (chave simétrica, mais simples)
  • RS256 — RSA com SHA-256 (chave assimétrica, mais seguro para APIs públicas)
  • ES256 — ECDSA com SHA-256 (compacto e moderno)

2. Payload (Claims)

Contém as claims — informações sobre o usuário e metadados do token:

{
  "sub": "user_123",
  "name": "Maria Silva",
  "email": "maria@email.com",
  "role": "admin",
  "iat": 1616239022,
  "exp": 1616242622
}

As claims padrão (registradas) mais importantes:

ClaimNomeDescrição
subSubjectIdentificador do usuário
iatIssued AtTimestamp de criação
expExpirationTimestamp de expiração
issIssuerQuem emitiu o token
audAudiencePara quem o token é destinado

3. Signature

A assinatura é criada combinando header + payload + secret:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

É a assinatura que garante que o token não foi alterado. Se alguém modificar o payload, a assinatura não vai bater e o servidor rejeitará o token.

Fluxo de Autenticação com JWT

O fluxo típico de autenticação funciona assim:

  1. Login: Usuário envia credenciais (email + senha) para /api/login
  2. Geração: Servidor valida credenciais e gera um JWT com os dados do usuário
  3. Armazenamento: Cliente recebe e armazena o token (cookie httpOnly ou localStorage)
  4. Uso: Em cada request, o cliente envia o token no header Authorization: Bearer <token>
  5. Verificação: Servidor verifica a assinatura e extrai os dados do token (sem consultar banco)
// Exemplo: enviando JWT em requisições
const response = await fetch('/api/profile', {
    headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
    }
});

Como Decodificar um JWT

No Terminal

# Decodificar payload (parte 2)
echo "eyJzdWIiOiIxMjM0NTY3ODkwIn0" | base64 -d
# {"sub":"1234567890"}

Em JavaScript

function decodeJWT(token) {
    const parts = token.split('.');
    if (parts.length !== 3) throw new Error('Token inválido');

    const header = JSON.parse(atob(parts[0]));
    const payload = JSON.parse(atob(parts[1]));

    return { header, payload };
}

const token = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.xxx';
const decoded = decodeJWT(token);
console.log(decoded.payload.sub); // "1234567890"

Em Python

import jwt  # pip install PyJWT

# Decodificar sem verificar assinatura (debug)
payload = jwt.decode(token, options={"verify_signature": False})
print(payload)

# Decodificar COM verificação (produção)
payload = jwt.decode(token, "minha-chave-secreta", algorithms=["HS256"])
print(payload)

Erros Comuns e Vulnerabilidades

1. Armazenar JWT no localStorage

O localStorage é acessível via JavaScript, o que significa que qualquer ataque XSS pode roubar o token. Preferível: armazene em um cookie httpOnly com flags Secure e SameSite.

2. Não validar o algoritmo

O ataque "alg: none" é clássico: o atacante modifica o header para "alg": "none" e remove a assinatura. Sempre valide que o algoritmo é o esperado no servidor.

// ❌ Vulnerável
jwt.verify(token, secret);

// ✅ Seguro — forçar algoritmo
jwt.verify(token, secret, { algorithms: ['HS256'] });

3. Tokens que nunca expiram

Tokens sem exp são um risco. Sempre defina um tempo de expiração curto (15–30 minutos) e use refresh tokens para renovar.

4. Secret fraco

Usar strings como "secret" ou "123456" permite ataques de força bruta. Use chaves geradas com pelo menos 256 bits de entropia:

# Gerar um secret seguro
openssl rand -hex 32

JWT vs. Sessions: Quando Usar Cada Um?

CritérioJWT (Stateless)Sessions (Stateful)
ArmazenamentoNo clienteNo servidor (Redis, DB)
EscalabilidadeExcelente (sem estado)Requer sessão compartilhada
RevogaçãoDifícil (precisa de blocklist)Fácil (deletar sessão)
SSR / Server-sideFunciona com cookiesPadrão nativo
MicrosserviçosIdealComplexo

Perguntas Frequentes

JWT é a mesma coisa que OAuth?

Não. OAuth 2.0 é um protocolo de autorização. JWT é um formato de token. O OAuth pode usar JWT como formato dos access tokens, mas são conceitos distintos.

Posso revogar um JWT?

Não diretamente, pois ele é stateless. A prática comum é manter uma blocklist de tokens revogados (ex: em Redis) ou usar tokens de curta duração + refresh tokens.

Devo usar JWT para tudo?

Não. Para apps monolíticos com renderização server-side, sessions tradicionais são mais simples e seguras. JWT brilha em APIs, SPAs e microsserviços.

🛠️ Experimente na prática

Use nossas ferramentas online gratuitas — sem cadastro, direto no navegador.

JWTautenticaçãotokensegurançaAPIOAuth