Desenvolvimento · Segurança

JWT explicado: como funciona a autenticação com token e os erros mais comuns

Edson Feitosa de Oliveira Junior
Edson Feitosa de Oliveira Junior Fundador e Engenheiro Líder · PruPru Digital Services

JWT (JSON Web Token) é um formato de token muito usado para autenticação em APIs. Depois que o usuário faz login, o servidor entrega um token assinado; nas próximas requisições, o cliente envia esse token e o servidor confere a assinatura para saber quem está chamando, sem precisar consultar uma sessão guardada. É simples de usar, mas cheio de detalhes que, quando ignorados, abrem falhas de segurança.

A estrutura de um JWT

Um JWT tem três partes separadas por pontos:

xxxxx.yyyyy.zzzzz
cabeçalho.payload.assinatura
  1. Cabeçalho (header): o tipo do token e o algoritmo de assinatura, como HS256 ou RS256.
  2. Payload: as informações (claims), como o identificador do usuário (sub), a data de expiração (exp), a data de emissão (iat) e perfis de acesso.
  3. Assinatura: calculada a partir do cabeçalho, do payload e de uma chave secreta ou privada.

Exemplo de payload decodificado:

{
  "sub": "1234",
  "nome": "Ana",
  "roles": ["cliente"],
  "iat": 1793635200,
  "exp": 1793636100
}

O ponto mais importante: JWT não é criptografado

As duas primeiras partes são apenas codificadas em Base64URL. Qualquer pessoa com o token consegue ler o payload. A assinatura garante que o conteúdo não foi alterado, não que ele é secreto. Por isso:

Como a validação funciona

Ao receber um token, o servidor deve:

  1. Verificar a assinatura com a chave correta.
  2. Conferir que o algoritmo é o esperado (não aceitar qualquer algoritmo informado no cabeçalho).
  3. Verificar a expiração (exp) e, se usados, o emissor (iss) e o público (aud).
  4. Só então confiar nas informações do payload.

Use bibliotecas consolidadas para isso, como o suporte a OAuth2 Resource Server do Spring Security, e nunca implemente a verificação manualmente.

HS256 ou RS256?

Com HS256, use uma chave longa e aleatória, guardada fora do código. Veja variáveis de ambiente e segredos.

Access token e refresh token

Um JWT não pode ser revogado facilmente antes de expirar, porque o servidor não guarda estado. A solução comum é usar dois tokens:

Assim, um access token roubado tem utilidade limitada no tempo, e o acesso pode ser cortado revogando o refresh token. Uma boa prática adicional é a rotação: cada uso do refresh token gera um novo e invalida o anterior.

Onde guardar o token no navegador

Esse é um dos debates mais comuns:

OpçãoRisco principalObservação
localStorageQualquer script na página pode ler (XSS)Simples, mas um XSS expõe o token
Memória da aplicação (variável JavaScript)Perde-se ao recarregar a páginaCombine com refresh token em cookie
Cookie HttpOnly, Secure, SameSiteExige proteção contra CSRFO JavaScript não consegue ler o cookie

Uma abordagem bastante adotada em SPAs: access token na memória e refresh token em cookie HttpOnly, Secure e com SameSite adequado, junto com proteção CSRF no endpoint de renovação. Se a sua aplicação usa cookies e recebe erros 403 em POST, o problema provavelmente é CSRF; veja o caso real em Spring Security 403 em POST com React.

Enviando o token

O padrão é o cabeçalho Authorization:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Se o front-end e a API estão em domínios diferentes, configure o CORS corretamente. Veja CORS: o que é e como resolver os erros.

Erros comuns

  1. Aceitar o algoritmo "none" ou deixar o cabeçalho escolher o algoritmo. Fixe o algoritmo esperado no servidor.
  2. Segredo fraco ou no código-fonte. Um segredo vazado no GitHub permite que qualquer pessoa crie tokens válidos.
  3. Tokens que nunca expiram.
  4. Dados sensíveis no payload.
  5. Logar o token completo nos logs da aplicação. Veja logs em produção.
  6. Confiar nos perfis do token para tudo quando as permissões mudam com frequência. Para mudanças imediatas, consulte o estado atual no servidor.
  7. Não usar HTTPS. Sem HTTPS, o token pode ser interceptado.

JWT é sempre a melhor opção?

Não. Para aplicações web tradicionais, em que o mesmo servidor entrega as páginas e a API, sessões com cookie são mais simples e fáceis de revogar. JWT faz mais sentido em APIs consumidas por vários clientes (web, aplicativo móvel, outros serviços) e em arquiteturas com vários serviços. Para entender a base, veja o que é uma API REST e códigos de status HTTP, especialmente a diferença entre 401 e 403.

Na prática da PruPru

Escolher entre JWT e sessão com cookie muda o que você precisa proteger. Num sistema com Spring Boot 3 e React feito pela PruPru, a autenticação usava sessão com cookie, e por isso a proteção CSRF era obrigatória. Foi ela que fez todo POST, PUT e DELETE voltar 403 depois da atualização para o Spring Security 6. Com JWT enviado no cabeçalho Authorization, esse risco específico some, mas aparecem outros, como guardar o token com segurança no navegador. O caso completo está em Spring Security retornando 403 em POST com React.

Sistemas sob medida

A PruPru desenvolve APIs, sistemas web e integrações com as mesmas práticas descritas neste guia. Se a sua empresa precisa de software bem construído, conheça os serviços.

Ver serviços →

Perguntas frequentes

JWT é criptografado?

Não, na forma mais comum (JWS). O cabeçalho e o payload são apenas codificados e qualquer pessoa pode lê-los. A assinatura garante a integridade. Existe o JWE, que criptografa o conteúdo, mas é menos usado.

Como fazer logout com JWT?

No cliente, descarte o access token. No servidor, revogue o refresh token. Como o access token tem vida curta, ele expira em poucos minutos. Para revogação imediata, é preciso manter uma lista de tokens bloqueados.

Qual o tempo de expiração ideal para um access token?

Em geral, entre 5 e 15 minutos, combinado com um refresh token de vida mais longa. O equilíbrio depende do risco da aplicação e da experiência desejada.

Posso guardar o JWT no localStorage?

Pode, mas qualquer vulnerabilidade de XSS permite que um script malicioso leia o token. Muitas aplicações preferem manter o access token em memória e o refresh token em cookie HttpOnly.

Falar no WhatsApp agora