OAuth 2.0 e JWT: Autenticação e Autorização Moderna para APIs REST

Proteger uma API REST não é apenas uma questão de autenticação (quem é você?), mas também de autorização (o que você pode fazer?). Neste artigo, vamos mergulhar nos dois pilares da segurança moderna de APIs: o protocolo OAuth 2.0 e o formato JWT (JSON Web Token).
O que é OAuth 2.0?
OAuth 2.0 é um protocolo de autorização que permite que aplicações obtenham acesso limitado a recursos em nome de um usuário. Diferente de um login tradicional onde você entrega sua senha para cada serviço, o OAuth 2.0 usa tokens de acesso com escopos bem definidos.
Criado pelo IETF (RFC 6749), o OAuth 2.0 é o padrão utilizado por gigantes como Google, GitHub, Facebook e Microsoft para autorizar aplicações de terceiros.
💡 "OAuth 2.0 não é um protocolo de autenticação — é um protocolo de autorização. Mas ele é frequentemente combinado com JWT para construir sistemas completos de autenticação."
Os 4 Papéis do OAuth 2.0
- Resource Owner (Proprietário do Recurso): O usuário que possui os dados. Ex: você no Google.
- Client (Cliente): A aplicação que quer acessar os dados. Ex: um app de terceiros.
- Authorization Server (Servidor de Autorização): Emite os tokens após autenticar o usuário. Ex: servidor do Google.
- Resource Server (Servidor de Recursos): Hospeda os dados protegidos e valida o token. Ex: API do Google Drive.
O que é JWT?
JWT (JSON Web Token) é um formato compacto e seguro para transmitir informações entre duas partes como um objeto JSON. Ele é autocontido — todas as informações necessárias estão dentro do próprio token.
Um JWT é composto por três partes separadas por pontos (.) e codificadas em Base64URL:
HEADER.PAYLOAD.SIGNATURE
# Exemplo:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkxlbyIsImlhdCI6MTUxNjIzOTAyMn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_aQssw5c
Estrutura do JWT
1. Header
Contém o tipo do token e o algoritmo de assinatura:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload (Claims)
Contém as claims — afirmações sobre o usuário e metadados do token. Existem claims registradas (padrão) e personalizadas:
{
"sub": "user_123", // Subject — ID do usuário
"name": "Leonardo Mendes", // Claim personalizada
"iat": 1747353600, // Issued At — emitido em
"exp": 1747360800, // Expiration — expira em
"iss": "https://api.exemplo.com", // Issuer — emissor
"aud": "app-frontend" // Audience — público-alvo
}
3. Signature
Garante que o token não foi adulterado. É gerada combinando header + payload + uma chave secreta:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
Fluxos de Autorização do OAuth 2.0
1. Authorization Code Flow (Recomendado)
É o fluxo mais seguro para aplicações web e mobile. O cliente nunca vê o token diretamente — ele recebe um código de autorização que é trocado por um token no backend.
Usuário → Frontend → Authorization Server → Código
↓
Backend (troca código por token)
↓
Token armazenado no servidor
Passo a passo:
- Usuário clica em "Login com Google"
- O frontend redireciona para o Google (Authorization Server) com os parâmetros:
client_id,redirect_uri,response_type=code,scope - Usuário faz login e autoriza a aplicação
- Google redireciona de volta com um
codena URL - O backend troca o
codepor umaccess_token(e opcionalmente umrefresh_token)
2. Client Credentials Flow
Usado para comunicação máquina-a-máquina (server-to-server). Não envolve usuário final:
POST /oauth/token HTTP/1.1
Content-Type: application/json
{
"grant_type": "client_credentials",
"client_id": "seu-client-id",
"client_secret": "seu-client-secret"
}
Resposta:
{
"access_token": "eyJhbGci...",
"token_type": "Bearer",
"expires_in": 3600
}
3. Implicit Flow (DEPRECATED)
Antigamente usado em SPAs, hoje é fortemente desencorajado por questões de segurança. Prefira o Authorization Code Flow com PKCE.
Implementação Prática: Autenticação com JWT em Node.js
Backend: Gerando Tokens
const jwt = require('jsonwebtoken');
function gerarToken(usuario) {
const payload = {
sub: usuario.id,
nome: usuario.nome,
email: usuario.email,
perfil: usuario.perfil
};
return jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: '1h',
issuer: 'https://api.exemplo.com'
});
}
// Uso no login:
app.post('/login', async (req, res) => {
const { email, senha } = req.body;
const usuario = await autenticarUsuario(email, senha);
if (!usuario) {
return res.status(401).json({ erro: 'Credenciais inválidas' });
}
const token = gerarToken(usuario);
res.json({ access_token: token, token_type: 'Bearer' });
});
Middleware de Autenticação
function authMiddleware(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ erro: 'Token não fornecido' });
}
// Formato esperado: "Bearer eyJhbGci..."
const parts = authHeader.split(' ');
if (parts.length !== 2 || parts[0] !== 'Bearer') {
return res.status(401).json({ erro: 'Formato inválido' });
}
const token = parts[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.usuario = decoded;
next();
} catch (err) {
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ erro: 'Token expirado' });
}
return res.status(401).json({ erro: 'Token inválido' });
}
}
// Protegendo rotas:
app.get('/api/perfil', authMiddleware, (req, res) => {
res.json({ usuario: req.usuario });
});
Refresh Token na Prática
Access tokens têm curta duração (15 min a 1 hora). Para evitar que o usuário faça login repetidamente, usamos refresh tokens:
function gerarRefreshToken(usuario) {
const payload = { sub: usuario.id, type: 'refresh' };
return jwt.sign(payload, process.env.JWT_REFRESH_SECRET, {
expiresIn: '7d'
});
}
app.post('/refresh', async (req, res) => {
const { refresh_token } = req.body;
try {
const decoded = jwt.verify(refresh_token, process.env.JWT_REFRESH_SECRET);
if (decoded.type !== 'refresh') {
return res.status(400).json({ erro: 'Token inválido' });
}
const usuario = await buscarUsuario(decoded.sub);
const novoAccessToken = gerarToken(usuario);
res.json({ access_token: novoAccessToken });
} catch (err) {
return res.status(401).json({ erro: 'Refresh token inválido ou expirado' });
}
});
Boas Práticas de Segurança
- Use HTTPS sempre: Tokens JWT trafegam no header da requisição. Sem HTTPS, eles podem ser interceptados.
- Armazene tokens com segurança: No frontend web, prefira
httpOnlycookies em vez delocalStorage(vulnerável a XSS). - Defina expiração curta: Access tokens de 15-60 minutos. Refresh tokens de 7-30 dias.
- Use escopos (scopes): Limite o que o token pode fazer. Ex:
read:posts,write:posts. - Não coloque dados sensíveis no payload: O JWT é apenas assinado, não criptografado. Qualquer um que decode o Base64URL consegue ler o payload.
- Blacklist de tokens: Para revogação imediata, mantenha uma blacklist em cache (Redis) de tokens invalidados.
OAuth 2.0 + JWT vs Alternativas
| Abordagem | Stateful? | Escalabilidade | Quando usar |
|---|---|---|---|
| OAuth 2.0 + JWT | Stateless | Excelente | APIs REST, microsserviços, SSO |
| Sessão com Cookie | Stateful | Limitada | Monólitos, apps server-render |
| API Key | Stateless | Boa | Machine-to-machine, serviços internos |
| Basic Auth | Stateless | Ruim | Apenas para testes ou legacy |
Ferramentas Populares
- Auth0: Plataforma completa de autenticação como serviço, com suporte nativo a OAuth 2.0 e JWT.
- Keycloak: Solução open-source de gerenciamento de identidade e acesso, ideal para self-hosted.
- NextAuth.js / Auth.js: Biblioteca de autenticação para Next.js e frameworks modernos.
- Passport.js: Middleware de autenticação flexível para Node.js com suporte a 500+ estratégias.
- jsonwebtoken (npm): Biblioteca oficial para criar e verificar JWTs em Node.js.
Conclusão
OAuth 2.0 e JWT formam a espinha dorsal da segurança em APIs modernas. Enquanto o OAuth 2.0 define como o acesso é autorizado — com fluxos bem definidos para cada cenário — o JWT fornece um formato leve, autocontido e seguro para transportar as informações de autenticação.
A combinação dos dois permite construir sistemas stateless e altamente escaláveis, onde qualquer serviço pode validar um token sem precisar consultar um banco de dados central. Isso é essencial em arquiteturas de microsserviços, APIs públicas e sistemas de SSO (Single Sign-On).
Lembre-se: segurança não é um produto, é um processo. Comece com o fluxo correto, aplique as boas práticas e revise sua implementação regularmente. 🚀







