JWT está em quase toda autenticação de API e aplicação web, e mesmo assim é cercado de mal-entendidos, quase todos sobre segurança. O maior deles: muita gente acha que o token é criptografado e que os dados dentro dele são secretos. Não são. Entender as três partes de um JWT, a diferença entre codificar e criptografar e o que separa decodificar de validar evita erros que expõem contas inteiras. Neste guia você vê o que é um JWT, como ele é montado, como funciona o fluxo de login, onde estão os riscos e por que nunca colar tokens sensíveis em qualquer lugar. Para inspecionar um token com segurança, use o decodificador de JWT.
Resposta rápida
- JWT é um token compacto e verificável com 3 partes: header.payload.signature, separadas por ponto (RFC 7519).
- Header e payload são só codificados em Base64URL, não criptografados: qualquer um lê o conteúdo sem chave.
- A assinatura garante integridade, não sigilo. Validar exige conferir a assinatura, a expiração (exp) e o emissor no servidor.
- Nunca ponha senha ou dado sensível no payload, e nunca cole tokens reais em sites desconhecidos.
O que é JWT e o problema que ele resolve
JWT (JSON Web Token) é um padrão aberto, definido na RFC 7519, para transmitir informações entre duas partes de forma compacta e verificável. O problema que ele ataca é a autenticação sem estado (stateless). No modelo antigo de sessão, o servidor guarda uma tabela de sessões e, a cada requisição, procura o usuário pelo id do cookie. Isso funciona, mas amarra o usuário a um servidor específico e cria trabalho de armazenamento e consulta.
Com JWT, a ideia se inverte. Depois do login, o servidor monta um token que já carrega quem é o usuário e o assina com uma chave. O cliente guarda esse token e o envia em cada requisição. O servidor só precisa conferir a assinatura para confiar no conteúdo, sem consultar banco de dados. Como a informação vive dentro do próprio token, qualquer servidor com a chave certa consegue validar, o que facilita escalar e distribuir a autenticação entre vários serviços. O payload é escrito em JSON, o mesmo formato do guia sobre o que é JSON.
As três partes: header, payload e assinatura
Um JWT é formado por três blocos separados por ponto. Cada bloco é codificado em Base64URL:
- Header: indica o tipo (JWT) e o algoritmo de assinatura (por exemplo, HS256 ou RS256).
- Payload: contém os claims, ou seja, os dados, como sub (id do usuário), permissões, iss (emissor), iat (emissão) e exp (expiração).
- Signature: a assinatura, calculada a partir do header, do payload e de uma chave, que garante que o token não foi adulterado.
Na prática, um token tem este formato (as quebras de linha abaixo são só para leitura; o token real é uma única linha com dois pontos):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. ← header
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. ← payload
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ← signatureRepare que cada parte parece embaralhada, mas não está protegida: é apenas texto codificado. Para entender essa codificação em si, veja o codificador Base64.
Base64URL não é criptografia (prova decodificando)
Esse é o mal-entendido número um sobre JWT. Base64URL é uma codificação, não uma cifra. Não existe segredo nem chave: qualquer pessoa converte de volta para o texto original em um clique. Um JWS assinado esconde a chave usada na assinatura, mas expõe todo o conteúdo do header e do payload. Decodificando os dois primeiros blocos do token acima, sai isto:
// header decodificado
{
"alg": "HS256",
"typ": "JWT"
}
// payload decodificado
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}Nada de chave, nada de servidor: o navegador faz isso sozinho. A lição prática é direta. Se você colocar CPF, senha, número de cartão ou qualquer dado sensível no payload, estará entregando esse dado a quem tiver o token. A assinatura protege contra alteração, não contra leitura. Confidencialidade de verdade só vem com HTTPS no transporte e, quando o conteúdo precisa ser secreto, com JWE (a variante que de fato cifra o payload).
As claims registradas
Os dados dentro do payload são os claims. A RFC 7519 padroniza sete claims (todas opcionais), que aparecem em praticamente todo JWT de autenticação. Conhecê-las ajuda a ler e a validar tokens:
| Claim | Nome | O que significa |
|---|---|---|
| iss | Issuer | Quem emitiu o token (o servidor de autenticação). |
| sub | Subject | O sujeito do token, em geral o id do usuário. |
| aud | Audience | Para quem o token se destina (a API que deve aceitá-lo). |
| exp | Expiration | Momento em que o token deixa de valer (timestamp). |
| nbf | Not Before | Momento a partir do qual o token passa a valer. |
| iat | Issued At | Quando o token foi emitido. |
| jti | JWT ID | Identificador único do token, útil para blocklist e evitar reuso. |
Além dessas, o payload pode ter claims públicas (nomes registrados por convenção) e privadas (combinadas entre quem emite e quem consome), como nome, papel ou lista de permissões. As três datas (exp, nbf, iat) usam o formato de timestamp NumericDate, ou seja, segundos desde 1º de janeiro de 1970 em UTC.
Como o token é assinado: HS256 x RS256
A assinatura é o que dá confiança ao JWT. Ela é calculada sobre o header e o payload já codificados, usando o algoritmo declarado no header. Os dois algoritmos mais comuns representam duas famílias diferentes:
| Ponto | HS256 | RS256 |
|---|---|---|
| Tipo | Simétrico (HMAC com SHA-256) | Assimétrico (RSA com SHA-256) |
| Chaves | Uma chave secreta compartilhada | Par de chaves: privada assina, pública verifica |
| Quem pode assinar | Qualquer um com a chave (assina e verifica) | Só quem tem a chave privada |
| Quem pode verificar | Só quem tem a mesma chave secreta | Qualquer um com a chave pública |
| Quando usar | Sistema único e mais simples | Vários serviços verificam o mesmo token |
A diferença tem peso de segurança. Com HS256, distribuir a chave para vários serviços verificarem também os transforma em capazes de forjar tokens. Com RS256, você entrega só a chave pública para os verificadores e mantém a privada isolada no emissor. Por isso RS256 é o padrão em arquiteturas com muitos serviços e provedores de identidade.
O fluxo de autenticação com JWT, passo a passo
Juntando as peças, um login com JWT costuma seguir esta sequência:
- O usuário envia e-mail e senha. Sobre boas práticas de senha, veja o guia do verificador de senha forte.
- O servidor confere as credenciais e, se estiverem certas, monta um payload (com sub, exp e o que mais for preciso) e assina o token com a chave.
- O token volta para o cliente, que o guarda (em cookie ou em memória, com os cuidados que veremos adiante).
- Em cada requisição protegida, o cliente envia o token no cabeçalho Authorization: Bearer <token>.
- O servidor verifica a assinatura, confere exp, nbf, iss e aud, e só então confia no conteúdo e responde.
Nenhuma etapa consulta uma tabela de sessões: a confiança vem da assinatura. Esse é o ganho e, ao mesmo tempo, a origem do maior desafio do JWT, a revogação, que veremos mais adiante.
Segurança: os erros que derrubam a proteção
A maioria das falhas com JWT não está no algoritmo, e sim em validação mal feita. Os pontos que a OWASP mais reforça:
- O ataque do algoritmo none: o atacante troca o header para alg none e remove a assinatura. Fixe o algoritmo esperado no servidor e rejeite none; nunca confie no algoritmo declarado pelo próprio token.
- Não validar a assinatura: decodificar não é validar. Um token só é confiável depois de a assinatura ser conferida com a chave correta.
- Ignorar o exp: aceitar um token expirado equivale a não ter expiração. Sempre cheque exp (e nbf, quando presente).
- Dado sensível no payload: o payload é legível. Nunca coloque senha, CPF, número de cartão ou segredo ali.
- Sem HTTPS: em trânsito sem TLS, o token pode ser interceptado e reutilizado como credencial. HTTPS é obrigatório.
- Confusão de chave HS/RS: em servidores mal configurados, um atacante pode assinar com a chave pública tratando-a como segredo HMAC. Aceite apenas o algoritmo previsto.
Trate o token de acesso como uma credencial viva: quem o tem, e enquanto ele valer, está logado. Para gerar e conferir hashes ao proteger dados, o gerador de hash ajuda a entender a diferença entre hash e assinatura.
Onde guardar o token no cliente
Depois do login, o navegador precisa guardar o token em algum lugar, e cada opção tem um risco diferente. Não há escolha perfeita:
- localStorage: simples de usar, mas qualquer script na página lê o token. Se houver uma falha de XSS, o atacante rouba o token. A superfície de risco é o XSS.
- Cookie HttpOnly + Secure: o JavaScript não consegue ler o cookie, o que neutraliza o roubo por XSS, mas o navegador o envia automaticamente, o que abre espaço para CSRF. A defesa vem de SameSite e de tokens anti-CSRF.
O trade-off é XSS x CSRF. Muitos times preferem o cookie HttpOnly com SameSite estrito por remover o token do alcance do JavaScript, mas a decisão depende do restante da arquitetura. Em qualquer caso, feche as portas de XSS (validando e escapando entradas) e sirva tudo por HTTPS.
JWT x sessão tradicional
JWT não é sempre melhor que a sessão clássica: são trocas diferentes. O quadro resume as três diferenças que mais pesam na decisão:
| Aspecto | Sessão tradicional | JWT |
|---|---|---|
| Onde fica o estado | No servidor; o cliente guarda só um id | No próprio token, assinado, no cliente |
| Escala e distribuição | Precisa compartilhar a sessão entre servidores | Qualquer servidor com a chave valida sozinho |
| Revogação | Imediata: basta apagar a sessão | Difícil: vale até expirar (precisa de blocklist) |
Em resumo: a sessão é fácil de invalidar e o JWT é fácil de distribuir. Se o seu sistema é um servidor único que precisa derrubar acessos na hora, a sessão costuma ser mais direta. Se você tem vários serviços validando o mesmo login, o JWT paga o custo.
O problema da revogação
Como o servidor valida o JWT só pela assinatura, ele não sabe, por conta própria, que um token foi revogado. Um token roubado continua funcionando até o exp. As saídas combinam bem:
- exp curto: tokens de acesso com poucos minutos de vida reduzem a janela de estrago em caso de vazamento.
- Refresh token: um segundo token, de vida mais longa e guardado com mais cuidado, permite obter novos tokens de acesso sem pedir a senha de novo.
- Blocklist: uma lista de tokens invalidados (por jti) consultada na validação, para logout, troca de senha ou suspeita de fraude. Isso reintroduz um pouco de estado, mas fecha o buraco da revogação.
Refresh tokens na prática
O par token de acesso mais refresh token é o desenho mais comum. O token de acesso é curto e vai em cada requisição; o refresh token é longo e fica guardado com mais proteção (em geral um cookie HttpOnly). Quando o token de acesso expira, o cliente troca o refresh por um novo acesso, sem novo login. Uma boa prática é a rotação: cada uso do refresh gera um novo e invalida o anterior, o que ajuda a detectar reuso indevido. Ao deslogar, o servidor descarta o refresh token e passa a barrar o acesso pela blocklist até ele expirar.
JWT x token opaco
Nem todo token de autenticação é um JWT. Um token opaco é só uma string aleatória sem significado por si: o servidor guarda, em um armazenamento, a quem aquele token pertence e o consulta a cada uso. Ele é o oposto do JWT em uma dimensão importante: o opaco carrega estado no servidor (fácil de revogar, precisa de consulta), enquanto o JWT carrega estado no token (stateless, difícil de revogar). Um token opaco também não vaza dados, porque não há nada legível dentro dele. A escolha entre os dois segue a mesma lógica de sessão x JWT: revogação imediata pende para o opaco, validação distribuída pende para o JWT.
Quando não usar JWT
JWT é ótimo, mas não é resposta para tudo. Pense duas vezes antes de adotá-lo quando:
- Você precisa revogar acessos na hora com garantia (banir uma sessão específica imediatamente). A sessão de servidor faz isso melhor.
- O sistema é um único servidor e uma sessão simples já resolve, sem a complexidade de assinatura e refresh.
- O payload cresce demais. Como o token viaja em cada requisição, um JWT grande vira desperdício de banda.
- Você precisaria colocar dado sensível no token para funcionar. Como o payload é legível, isso é um sinal de que o desenho está errado.
Por que não colar tokens sensíveis online
Como o payload é legível e um token de acesso válido funciona como senha, colar um JWT real de produção em um site desconhecido é arriscado: você pode entregar tanto os dados quanto uma credencial ativa. Use ferramentas que processam localmente no navegador, como o decodificador de JWT do ValorFinal, que não envia o token a nenhum servidor. Para entender o JSON do payload, veja o guia o que é JSON; para gerar hashes, o gerador de hash; e para outras tarefas de codificação, o codificador de URL e o gerador de UUID.
Limitações deste guia
Este conteúdo é educativo e não cobre todas as nuances de uma implementação segura de autenticação. Detalhes como escolha de biblioteca, rotação de chaves, formatos de armazenamento e políticas de expiração dependem do seu contexto. Para sistemas em produção, siga as recomendações oficiais (RFC 7519 e OWASP) e prefira bibliotecas consolidadas a implementar assinatura e validação do zero. Veja também como validamos os cálculos.
Fontes oficiais
- RFC 7519 (IETF): especificação do JSON Web Token, incluindo a lista de claims registradas.
- jwt.io (Introdução ao JWT): referência prática da estrutura e dos algoritmos, com exemplo decodificado.
- OWASP (JWT Cheat Sheet): boas práticas de segurança e falhas comuns, como o ataque do algoritmo none.
- MDN Web Docs (JWT): definição de referência e contexto de uso na web.
Conclusão
Um JWT tem três partes, header, payload e assinatura, e o ponto que evita os erros mais graves é entender que codificar não é criptografar e decodificar não é validar. O payload é legível por qualquer um, então nunca guarde segredo nele; a assinatura garante integridade, não sigilo, e só vale depois de conferida com a chave e o algoritmo esperados no servidor, junto do exp. Como o token é válido até expirar, use exp curto, refresh token e blocklist quando precisar revogar. Para inspecionar um token com segurança, use o decodificador de JWT, entenda o JSON do payload e a codificação Base64, e conheça as demais ferramentas de tecnologia.
