Pular para o conteúdo principal

Autenticação com JWT: Um Guia Passo a Passo para Proteger suas APIs

Publicado em 17 de dezembro de 20250 min de leitura
Imagem de tecnologia relacionada ao artigo autenticacao-com-jwt-guia-passo-a-passo

Autenticação com JWT: Um Guia Passo a Passo para Proteger suas APIs

Em uma aplicação web moderna, nem todos os recursos da sua API devem ser públicos. Dados de usuários, painéis administrativos e funcionalidades exclusivas para membros precisam de uma camada de proteção para garantir que apenas pessoas autorizadas possam acessá-los. É aqui que entra a autenticação.

Enquanto a abordagem tradicional envolvia o uso de sessões armazenadas no servidor, a ascensão das APIs RESTful e de clientes desacoplados exigiu uma abordagem mais robusta e independente. O JSON Web Token (JWT) não é apenas uma conveniência, mas o padrão que permite que sistemas modernos escalem sem perder a segurança.

Nas próximas linhas, vamos decodificar o funcionamento interno do JWT e implementar um fluxo de autenticação real, saindo da teoria para um código que você pode subir para produção.

O Problema das Sessões Tradicionais

No modelo clássico, após o login, o servidor criava uma sessão, armazenava seu ID em memória ou em um banco de dados e enviava um cookie de sessão para o cliente. A cada requisição, o cliente enviava o cookie, o servidor verificava a sessão e respondia.

Isso funciona, mas tem desvantagens em arquiteturas modernas:

  • Estado no Servidor (Stateful): O servidor precisa manter o controle de todas as sessões ativas. Isso dificulta a escalabilidade horizontal, pois se você adicionar mais servidores, precisará de um mecanismo complexo para compartilhar o estado da sessão entre eles.
  • Problemas com CORS: Cookies e requisições de diferentes domínios (CORS) nem sempre se dão bem.

O que é um JWT (JSON Web Token)?

Um JWT é um padrão aberto (RFC 7519) que define uma maneira compacta e autossuficiente de transmitir informações entre duas partes de forma segura, como um objeto JSON. A grande vantagem é que ele é stateless: o servidor não precisa guardar nenhuma informação sobre o usuário para validá-lo. Toda a informação necessária está contida no próprio token.

Um JWT é composto por três partes, separadas por pontos (.): header.payload.signature

  1. Header (Cabeçalho): Contém metadados sobre o token, como o tipo (JWT) e o algoritmo de criptografia usado (HS256, RS256, etc.). { "alg": "HS256", "typ": "JWT" }
  2. Payload (Carga Útil): Contém as "reivindicações" (claims), que são as informações que você quer transmitir sobre o usuário, como o ID, nome e permissões. Existem claims registrados (como iss - emissor, exp - data de expiração) e claims que você pode definir. { "sub": "12345", "name": "John Doe", "admin": true }
  3. Signature (Assinatura): Esta é a parte mais importante para a segurança. A assinatura é criada combinando o header, o payload e um segredo (secret) conhecido apenas pelo servidor, e passando tudo por um algoritmo de criptografia. HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

A assinatura garante que o token não foi modificado. Se um invasor tentar alterar o payload (por exemplo, mudar "admin": false para "admin": true), a assinatura não irá mais corresponder, e o servidor rejeitará o token.

Importante: O Header e o Payload são apenas codificados em Base64, não criptografados. Qualquer um pode decodificá-los. Nunca armazene informações sensíveis (como senhas) no payload de um JWT.

O Fluxo de Autenticação com JWT

  1. Login: O usuário envia suas credenciais (e-mail e senha) para um endpoint de login (/api/login).
  2. Verificação: O servidor verifica se as credenciais são válidas, consultando o banco de dados.
  3. Geração do Token: Se as credenciais estiverem corretas, o servidor cria um JWT. Ele define um payload (geralmente com o ID do usuário) e assina o token com uma chave secreta.
  4. Envio do Token: O servidor retorna o JWT para o cliente.
  5. Armazenamento no Cliente: O cliente (navegador, app mobile) armazena o token de forma segura (geralmente em localStorage, sessionStorage ou em um cookie HttpOnly).
  6. Requisições Autenticadas: Para cada requisição subsequente a uma rota protegida, o cliente envia o JWT no cabeçalho Authorization. Authorization: Bearer <seu_token_jwt>
  7. Verificação no Servidor: Em cada rota protegida, o servidor pega o token do cabeçalho, verifica a assinatura usando a mesma chave secreta e, se for válido, processa a requisição. Se a assinatura for inválida ou o token estiver expirado, ele retorna um erro 401 Unauthorized.

Mão na Massa: Implementando JWT em Node.js com Express

1. Instale as dependências:

bash
# Framework web, biblioteca para JWT e para criptografar senhas
npm install express jsonwebtoken bcryptjs

2. Crie a Rota de Login:

javascript
// server.js (simplificado)
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

const app = express();
app.use(express.json());

// Em uma aplicação real, isso viria de um banco de dados
const users = []; 
const JWT_SECRET = 'seu_segredo_super_secreto'; // NUNCA exponha isso no código! Use variáveis de ambiente.

// Rota para registrar um novo usuário
app.post('/register', async (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);
  users.push({ username, password: hashedPassword });
  res.status(201).send('Usuário registrado!');
});

// Rota de login
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);

  if (!user || !await bcrypt.compare(password, user.password)) {
    return res.status(401).send('Credenciais inválidas');
  }

  // Gera o token com o nome de usuário no payload
  const token = jwt.sign({ username: user.username }, JWT_SECRET, { expiresIn: '1h' });

  res.json({ token });
});

app.listen(3000, () => console.log('Servidor rodando'));

3. Crie o Middleware de Verificação:

Um middleware é uma função que intercepta as requisições antes que elas cheguem às rotas. É o lugar perfeito para verificar o JWT.

javascript
// middleware/auth.js
const jwt = require('jsonwebtoken');
const JWT_SECRET = 'seu_segredo_super_secreto';

function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

  if (token == null) {
    return res.sendStatus(401); // Se não há token, não autorizado
  }

  jwt.verify(token, JWT_SECRET, (err, user) => {
    if (err) {
      return res.sendStatus(403); // Se o token não for válido, proibido
    }
    req.user = user;
    next(); // Passa para a próxima rota
  });
}

module.exports = authenticateToken;

4. Proteja as Rotas:

Agora, basta aplicar o middleware nas rotas que você quer proteger.

javascript
// server.js (continuação)
const authenticateToken = require('./middleware/auth');

app.get('/perfil', authenticateToken, (req, res) => {
  // Graças ao middleware, req.user contém o payload do token
  res.send(`Bem-vindo, ${req.user.username}! Este é o seu perfil.`);
});

Agora, se você tentar acessar /perfil sem um token válido no cabeçalho Authorization, receberá um erro 401 ou 403.

Conclusão

A autenticação baseada em JWT é um padrão poderoso e flexível para proteger APIs modernas. Por ser stateless, ela simplifica a arquitetura e facilita a escalabilidade, tornando-se a escolha ideal para Single-Page Applications, microserviços e aplicações mobile.

Lembre-se sempre das boas práticas de segurança: use um segredo forte (armazenado em variáveis de ambiente), defina um tempo de expiração curto para os tokens e nunca, jamais, coloque dados sensíveis no payload. Dominar o fluxo de JWT é uma habilidade essencial para qualquer desenvolvedor backend que leve a segurança a sério.


Glossário Técnico

  • Stateless: Arquitetura onde o servidor não armazena informações sobre o estado do cliente entre as requisições, dependendo apenas do token enviado.
  • Base64URL: Método de codificação de dados binários em texto que é seguro para ser usado em URLs e nomes de arquivos.
  • Claims (Reivindicações): Pedaços de informação afirmados sobre um assunto (geralmente o usuário) dentro do payload de um JWT.
  • HMAC (Hash-based Message Authentication Code): Tipo de autenticação que utiliza uma função hash combinada com uma chave secreta.
  • HttpOnly Cookie: Opção de segurança que impede que scripts do lado do cliente (JavaScript) acessem o cookie, prevenindo ataques XSS.

Referências

  1. JWT.io. Introduction to JSON Web Tokens. O site de referência da comunidade para depurar e aprender tudo sobre a estrutura de tokens.
  2. Auth0 Blog. JWT Handbook. Um guia completo e aprofundado sobre padrões de autenticação moderna e segurança de APIs.
  3. IETF Datatracker. RFC 7519: JSON Web Token (JWT). A especificação técnica original que define os padrões do protocolo JWT no nível da internet.
  4. DigitalOcean. How To Authenticate a Node.js API with JWT. Tutorial prático focado em implementação real para desenvolvedores Node.js.
  5. OWASP. JSON Web Token Cheat Sheet. Lista de práticas recomendadas de segurança para evitar vulnerabilidades comuns em tokens.
Imagem de tecnologia relacionada ao artigo autenticacao-com-jwt-guia-passo-a-passo