Autenticação JWT: como proteger suas APIs de forma moderna

Rocketseat

Rocketseat

4 min de leitura
node
Fala, dev! Se você já se deparou com o desafio de proteger uma API, provavelmente ouviu falar sobre autenticação e, mais especificamente, sobre JWT. Parece complexo? Talvez. Mas e se eu te disser que entender JWT pode ser o que vai impulsionar a segurança e a escalabilidade dos seus projetos?
Muitas pessoas desenvolvedoras sentem um frio na barriga quando o assunto é autenticação. Gerenciar sessões no servidor, garantir que tudo escale corretamente e, claro, não deixar nenhuma brecha de segurança pode ser uma grande dor de cabeça. É exatamente aqui que o JSON Web Token (JWT) entra em cena, oferecendo uma abordagem moderna e stateless.
Se você quer entender de uma vez por todas como essa tecnologia funciona, quando usá-la e, o mais importante, como implementá-la de forma segura, você chegou ao lugar certo. Bora codar e descobrir juntos os segredos da autenticação JWT!

O que é JWT e por que você deveria se importar?

Vamos direto ao ponto. JWT (JSON Web Token) é um padrão aberto que define uma maneira compacta e autônoma de transmitir informações de forma segura entre duas partes. Pense nele como um passaporte digital: ele carrega suas informações (quem você é e o que pode fazer) e tem uma assinatura que garante sua autenticidade.
A grande virada de chave do JWT é ser stateless (sem estado). Isso significa que o servidor não precisa guardar nenhuma informação sobre a sua sessão. Todas as informações necessárias estão dentro do próprio token. Isso simplifica a arquitetura, especialmente em ambientes de microsserviços ou quando você tem um front-end (como um app mobile ou uma SPA) totalmente desacoplado do back-end.

A anatomia de um token: desvendando o header, payload e signature

Um JWT é uma string longa, mas na verdade ele é composto por três partes, separadas por pontos:
Header - (clique para expandir):
Contém metadados sobre o token. Geralmente, informa o tipo do token (typ, que é "JWT") e o algoritmo de assinatura usado (alg, como HS256 ou RS256).
{ "alg": "HS256", "typ": "JWT" }
Payload - (clique para expandir):
É aqui que a “mágica” acontece. O payload contém as claims (declarações), que são as informações sobre o usuário e outros dados relevantes. Existem claims registradas (padrão, como sub - o ID do usuário, e exp - a data de expiração), e você pode adicionar as suas próprias.
{ "sub": "user-123", "name": "Laís", "admin": false, "exp": 1644768000 }
O payload é apenas codificado (em Base64), não criptografado. Qualquer pessoa pode decodificá-lo. Portanto, nunca coloque informações sensíveis, como senhas, aqui dentro!
Signature - (clique para expandir):
Esta é a parte que garante a segurança. A assinatura é gerada combinando o header, o payload e uma chave secreta (que só o servidor conhece), tudo isso passado pelo algoritmo de assinatura. Se alguém tentar alterar o header ou o payload, a assinatura não vai mais corresponder, e o token será invalidado. É a prova de que o "passaporte" não foi falsificado.

O fluxo de autenticação na prática: do login à validação

Faz sentido? Agora vamos ver como isso funciona numa aplicação real.
  • Login do usuário: onde o user envia suas credenciais (ex: email e senha) para a sua API.
  • Validação: o servidor verifica se as credenciais estão corretas no banco de dados.
  • Geração do token: se tudo estiver certo, o servidor cria um JWT com as informações do usuário no payload e o assina com a chave secreta.
  • Envio ao cliente: o servidor retorna o JWT para a aplicação cliente (o navegador ou app mobile).
  • Armazenamento: o cliente armazena esse token de forma segura.
  • Requisições futuras: para cada requisição a uma rota protegida, o cliente envia o JWT no cabeçalho Authorization, geralmente no formato Bearer <token>.
  • Verificação no servidor: a cada requisição recebida, o servidor pega o token, verifica sua assinatura para garantir que ele é autêntico e não foi modificado. Se a assinatura for válida e o token não tiver expirado, o acesso é liberado.

JWT vs Sessões: a batalha pela autenticação moderna

Uma dúvida comum é: por que usar JWT em vez do sistema tradicional de sessões com cookies? A resposta depende do contexto, mas aqui estão os pontos principais:
Característica
Autenticação com Sessão (Stateful)
Autenticação com JWT (Stateless)
Armazenamento
O servidor armazena o ID da sessão.
O cliente armazena o token. O servidor não guarda nada.
Escalabilidade
Mais difícil de escalar horizontalmente (precisa de sticky sessions ou um banco de sessões compartilhado).
Escala facilmente. Qualquer servidor com a chave secreta pode validar o token.
Performance
Requer uma consulta ao banco de dados ou cache a cada requisição para validar a sessão.
A validação é feita em memória, apenas com cálculo criptográfico. Mais rápido.
Uso
Ideal para aplicações web tradicionais, monolíticas.
Perfeito para SPAs, APIs, microsserviços e apps mobile.
Revogação
Fácil de invalidar. Basta deletar a sessão do servidor.
Mais complexo. Por ser stateless, um token é válido até expirar.

Implementando autenticação JWT

Teoria é legal, mas é na prática que a gente aprende de verdade. Vamos construir uma implementação básica de autenticação JWT usando Node.js e a biblioteca jsonwebtoken.
Gerando seu primeiro token em Node.js - (clique para expandir):
Primeiro, instale as dependências: npm install jsonwebtoken bcrypt.
// Exemplo de código no momento do login const jwt = require('jsonwebtoken'); const bcrypt = require('bcrypt'); // Suponha que você já validou o usuário e a senha // user.id e user.name viriam do seu banco de dados async function handleLogin(req, res) { const { email, password } = req.body; // Lógica para encontrar o usuário e validar a senha com bcrypt... const user = { id: 'user-123', name: 'Rodrigo' }; // Exemplo de usuário // Se as credenciais estiverem corretas: const payload = { userId: user.id, name: user.name }; const secret = process.env.JWT_SECRET; // Guarde seu segredo em variáveis de ambiente! const options = { expiresIn: '900000ms' }; // Token expira em 15 minutos const token = jwt.sign(payload, secret, options); res.json({ accessToken: token }); }
 
Protegendo rotas com um middleware de autenticação - (clique para expandir):
Agora, vamos criar uma função de middleware para verificar o token em rotas que exigem autenticação.
// middleware/authenticateToken.js const jwt = require('jsonwebtoken'); function authenticateToken(req, res, next) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Formato "Bearer TOKEN" if (token == null) { return res.sendStatus(401); // Se não há token, não autorizado } jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) { return res.sendStatus(403); // Se o token não for válido, acesso proibido } // O payload decodificado é adicionado ao objeto da requisição req.user = user; next(); // Passa para a próxima função (o controller da rota) }); } // Em seu arquivo de rotas: // app.get('/perfil', authenticateToken, (req, res) => { ... });

Como não deixar brechas no seu JWT

Usar JWT é ótimo, mas uma implementação descuidada pode abrir portas para ataques. Vamos ver como se proteger.

Onde guardar o token? A treta do localStorage vs HttpOnly cookies

Esta é uma das maiores discussões.
  • localStorage: é a forma mais simples. O JavaScript do seu front-end pode acessar e enviar o token facilmente. O problema: vulnerável a ataques de Cross-Site Scripting (XSS). Se um invasor injetar um script malicioso na sua página, ele pode roubar o token.
  • HttpOnly cookies: são cookies que não podem ser acessados via JavaScript. O navegador os anexa automaticamente a cada requisição ao seu domínio. Isso mitiga o risco de roubo de token por XSS. O problema: requer proteção contra ataques de Cross-Site Request Forgery (CSRF).
Para a maioria das aplicações web, usar HttpOnly cookies é a abordagem mais segura, desde que você implemente uma estratégia anti-CSRF (como tokens CSRF).

A importância dos refresh tokens para uma segurança duradoura

Como vimos, access tokens devem ter vida curta (ex: 15 minutos). Mas você não quer forçar o usuário a fazer login a cada 15 minutos, certo?
A solução é usar refresh tokens. O fluxo é assim:
  1. No login, o servidor gera dois tokens: um access token (curto) e um refresh token (longo, ex: 7 dias).
  1. O access token é usado para acessar as rotas protegidas.
  1. Quando o access token expira, o cliente usa o refresh token para solicitar um novo access token em um endpoint específico (ex: /refresh_token), sem precisar das credenciais do usuário novamente.
Isso combina segurança (tokens de acesso que expiram rápido) com uma boa experiência para o usuário.

Vulnerabilidades comuns e como se defender

  • Algoritmo none: alguns servidores aceitavam tokens com o algoritmo de assinatura definido como "none". Um invasor poderia simplesmente remover a assinatura e acessar o sistema. Mitigação: Sua biblioteca de validação deve ter uma lista de algoritmos permitidos (ex: ['HS256', 'RS256']).
  • Chaves Secretas Fracas: se sua chave secreta for "123456", ela pode ser quebrada por força bruta. Mitigação: Use segredos longos, complexos e aleatórios, e guarde-os em variáveis de ambiente, nunca no código.
  • Vazamento de Informações no Payload: lembre-se, o payload é visível. Mitigação: Nunca coloque dados sensíveis nele.

E agora? Dando o próximo passo na sua jornada com APIs

Você desvendou o que é um JWT, entendeu sua estrutura, viu como implementar e, o mais importante, como pensar em segurança. A autenticação é um pilar no desenvolvimento de qualquer API robusta, e dominar JWT te coloca em outro nível como pessoa desenvolvedora.
O conhecimento que você construiu aqui é a base para criar aplicações mais seguras e escaláveis.
🚀
Se você quer ir muito além e dominar não só a autenticação, mas toda a construção de aplicações back-end com as tecnologias mais modernas do mercado, dá uma olhada na nossa Formação Full-Stack. Lá, a gente mergulha de cabeça em projetos práticos, construindo aplicações completas do zero, sempre com a mão no código.

Perguntas frequentes (FAQ)

  • É possível invalidar (fazer logout) um JWT antes que ele expire? Por serem stateless, não há uma forma direta no servidor. A abordagem mais comum é criar uma "blocklist" (lista de bloqueio) em um banco de dados rápido como o Redis. Antes de validar um token, você verifica se ele não está nessa lista.
  • JWT é o mesmo que OAuth? Não. OAuth 2.0 é um protocolo de autorização (para delegar acesso), enquanto JWT é um formato de token. Eles são frequentemente usados juntos: um servidor OAuth pode emitir JWTs como tokens de acesso.
  • Devo usar HS256 ou RS256? HS256 (simétrico) usa a mesma chave para assinar e verificar. É mais simples. RS256 (assimétrico) usa um par de chaves (privada para assinar, pública para verificar). É ideal quando a verificação precisa ser feita por um serviço diferente do que emitiu o token, comum em microsserviços.
Artigos_

Explore conteúdos relacionados

Descubra mais artigos que complementam seu aprendizado e expandem seu conhecimento.