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

Rocketseat

Navegação Rápida:
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 formatoBearer <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:
- No login, o servidor gera dois tokens: um
access token
(curto) e umrefresh token
(longo, ex: 7 dias).
- O
access token
é usado para acessar as rotas protegidas.
- Quando o
access token
expira, o cliente usa orefresh token
para solicitar um novoaccess 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.