Autenticacao JWT: Implementacao Passo a Passo em API
Implementar autenticacao JWT em uma API pode parecer complexo, mas com este guia passo a passo voce entendera cada etapa. Do conceito ao codigo funcional, aprenda a proteger endpoints, gerar tokens seguros e evitar vulnerabilidades comuns.
Implementar autenticacao JWT em uma API pode parecer complexo, mas com este guia passo a passo voce entendera cada etapa. Do conceito ao codigo funcional, aprenda a proteger endpoints, gerar tokens seguros e evitar vulnerabilidades comuns.
O resultado esperado ao final deste guia e uma API funcional que exige autenticacao JWT para acessar rotas protegidas, com tokens que expiram e sao validados a cada requisicao. Antes de comecar, certifique-se de ter um ambiente Node.js configurado (versao 18 ou superior) e um banco de dados simples para armazenar usuarios (pode ser SQLite ou um array em memoria para testes). Nao usaremos frameworks externos de autenticacao para que voce entenda cada peca do quebra-cabeca.
Passo 1: Instalar as dependencias essenciais
Crie um projeto Node com npm init -y e instale tres pacotes: express (servidor web), jsonwebtoken (biblioteca oficial JWT) e bcrypt (para hashear senhas). Execute:
npm install express jsonwebtoken bcrypt
A biblioteca jsonwebtoken e mantida pela comunidade e implementa o padrao RFC 7519. Ela oferece metodos sign() para criar tokens e verify() para valida-los. O bcrypt e essencial porque armazenar senhas em texto puro e a falha de seguranca mais comum entre iniciantes. Um erro frequente aqui e esquecer de adicionar dotenv para gerenciar variaveis de ambiente, mas, por ora, manteremos o segredo do token hardcoded apenas para aprendizado.
Passo 2: Criar o endpoint de registro de usuario
Antes de autenticar, precisamos de usuarios no sistema. Crie um arquivo server.js e configure um array usuarios (simulando um banco). O endpoint POST /registrar deve receber email e senha no corpo da requisicao. Hasheie a senha com bcrypt.hashSync(senha, 10) antes de armazenar:
const express = require('express'); const bcrypt = require('bcrypt'); const app = express(); app.use(express.json());
let usuarios = [];
app.post('/registrar', (req, res) => { const { email, senha } = req.body; if (!email || !senha) return res.status(400).json({ erro: 'Email e senha obrigatorios' }); const hash = bcrypt.hashSync(senha, 10); usuarios.push({ email, senha: hash }); res.status(201).json({ mensagem: 'Usuario registrado' }); });
Um erro comum e nao validar se o email ja existe. Para um guia completo, adicione uma verificacao antes de inserir: if (usuarios.find(u => u.email === email)) return res.status(409).json(...). O custo 10 do bcrypt e um equilibrio razoavel entre seguranca e desempenho em aplicacoes de pequeno porte.
Passo 3: Implementar o login e gerar o token JWT
O endpoint POST /login recebe email e senha. Compare a senha fornecida com o hash armazenado usando bcrypt.compareSync(). Se coincidirem, gere um token com jwt.sign():
const jwt = require('jsonwebtoken'); const SEGREDO = 'minha-chave-super-secreta';
app.post('/login', (req, res) => { const { email, senha } = req.body; const usuario = usuarios.find(u => u.email === email); if (!usuario || !bcrypt.compareSync(senha, usuario.senha)) { return res.status(401).json({ erro: 'Credenciais invalidas' }); } const token = jwt.sign({ email: usuario.email }, SEGREDO, { expiresIn: '1h' }); res.json({ token }); });
O payload do token (primeiro argumento) deve conter apenas dados nao sensiveis, nunca coloque a senha ou informacoes de pagamento. O expiresIn: '1h' define que o token expira em uma hora. Uma dica importante: em producao, o segredo deve vir de uma variavel de ambiente (process.env.JWT_SECRET), nunca hardcoded. Um erro comum e usar expiresIn: 0 ou nao definir expiracao, criando tokens eternos que aumentam o risco de vazamento.
Passo 4: Criar o middleware de autenticacao
Para proteger rotas, precisamos de um middleware que extraia o token do header Authorization, verifique sua assinatura e, se valido, permita o acesso. Crie a funcao autenticarJWT:
function autenticarJWT(req, res, next) { const authHeader = req.headers.authorization; if (!authHeader) return res.status(401).json({ erro: 'Token nao fornecido' }); const token = authHeader.split(' ')[1]; // Formato: Bearer <token> try { const decoded = jwt.verify(token, SEGREDO); req.usuario = decoded; // Disponivel nas rotas seguintes next(); } catch (erro) { return res.status(403).json({ erro: 'Token invalido ou expirado' }); } }
O padrao Bearer <token> e o mais utilizado em APIs REST. Um erro comum e esperar o token no corpo da requisicao ou como query string, isso e menos seguro e nao segue convencoes. Se o token expirou, o jwt.verify() lanca um erro TokenExpiredError; o codigo acima trata genericamente, mas voce pode diferenciar as mensagens para melhor experiencia do usuario.
Passo 5: Proteger rotas com o middleware
Agora, aplique o middleware a qualquer rota que exija autenticacao. Por exemplo, uma rota GET /perfil que retorna dados do usuario logado:
app.get('/perfil', autenticarJWT, (req, res) => { res.json({ mensagem: Bem-vindo, ${req.usuario.email}! }); });
Se o token for valido, req.usuario contem o payload decodificado (neste caso, o email). Caso contrario, o middleware interrompe a requisicao e retorna erro 401 ou 403. Para testar, use ferramentas como Postman ou Insomnia: faca login, copie o token retornado, cole no header Authorization: Bearer <token> e acesse /perfil. Um erro comum aqui e esquecer de usar app.use(express.json()) no inicio, o que impede a leitura do corpo das requisicoes POST.
Passo 6: Adicionar refresh token (opcional, mas recomendado)
Tokens de acesso com expiracao curta (15-30 minutos) sao mais seguros, mas forcam o usuario a fazer login frequentemente. A solucao e implementar um refresh token: um token de longa duracao (7 dias) armazenado no servidor que permite obter novos tokens de acesso sem reautenticar. Crie um endpoint POST /refresh que recebe o refresh token, valida-o e retorna um novo access token:
let refreshTokens = [];
app.post('/refresh', (req, res) => { const { refreshToken } = req.body; if (!refreshToken || !refreshTokens.includes(refreshToken)) { return res.status(403).json({ erro: 'Refresh token invalido' }); } const decoded = jwt.verify(refreshToken, SEGREDO_REFRESH); const novoAccessToken = jwt.sign({ email: decoded.email }, SEGREDO, { expiresIn: '15m' }); res.json({ accessToken: novoAccessToken }); });
Um erro comum e usar o mesmo segredo para access e refresh tokens, se um vazar, ambos estao comprometidos. Use chaves diferentes (SEGREDO_REFRESH). Alem disso, nunca armazene refresh tokens no lado do cliente sem protecao; em aplicacoes web, prefira cookies httpOnly.
Checklist do que foi implementado
- [ ] Endpoint
POST /registrarcom hash de senha usando bcrypt - [ ] Endpoint
POST /loginque gera token JWT com expiracao de 1 hora - [ ] Middleware
autenticarJWTque valida token do header Authorization - [ ] Rota protegida
GET /perfilque retorna dados do usuario autenticado - [ ] (Opcional) Sistema de refresh token com segredo separado
Perguntas Frequentes
O que e o payload de um token JWT?
O payload e a parte do token que contem as claims, informacoes sobre o usuario e metadados do token. Exemplos: sub (identificador do usuario), iat (timestamp de criacao) e exp (timestamp de expiracao). Nao coloque dados sensiveis, pois o payload e apenas codificado em Base64, nao criptografado, qualquer um que interceptar o token pode decodifica-lo.
Qual a diferenca entre JWT e sessao tradicional?
Na autenticacao por sessao, o servidor armazena o estado do usuario (ex.: Redis, banco). No JWT, o token carrega todas as informacoes necessarias, eliminando a necessidade de consulta ao servidor a cada requisicao. Isso torna APIs stateless e mais faceis de escalar horizontalmente. A desvantagem e que revogar um JWT antes da expiracao exige uma blacklist.
Como renovar um token JWT expirado sem forcar login?
Use um refresh token de longa duracao. Quando o access token expirar, o cliente envia o refresh token para um endpoint especifico (ex.: /refresh) e recebe um novo access token. O refresh token deve ser armazenado com seguranca, em apps web, use cookies httpOnly; em mobile, armazene no Keychain/Keystore do dispositivo.
E seguro armazenar o JWT no localStorage?
Nao e recomendado. O localStorage e acessivel por JavaScript, tornando o token vulneravel a ataques XSS (Cross-Site Scripting). Prefira cookies httpOnly e secure, que nao sao acessiveis via JS, ou utilize mecanismos como armazenamento em memoria com refresh token em cookie. Em aplicacoes mobile, use armazenamento seguro nativo.
O que fazer se o segredo JWT vazar?
Troque imediatamente o segredo e regenere todos os tokens. Todos os tokens existentes se tornarao invalidos, forcando os usuarios a fazer login novamente. Para minimizar danos, use segredos rotativos e mantenha um registro de versoes do segredo (key rotation) para permitir que tokens emitidos com o segredo antigo ainda sejam validos por um periodo de transicao.
Meu token tem 500 caracteres, isso e normal?
Sim. O tamanho do token depende do algoritmo de assinatura (HS256 gera tokens menores que RS256) e da quantidade de claims no payload. Um token com email, iat e exp e assinatura HS256 geralmente fica entre 200 e 400 caracteres. Se estiver muito maior (acima de 1 KB), voce pode estar incluindo dados desnecessarios no payload.
Ptolomeu Rangel Sicupira
Pesquisador de tendências e cultura digital
Lê a internet como antropólogo; conecta meme, comportamento e estratégia de marca.
Ver todos os artigos →