Introdução: por que OAuth 2.0 e JWT são o padrão da autorização moderna
\nNo desenvolvimento web moderno, autenticação e autorização seguras são componentes criticamente importantes de qualquer aplicação. OAuth 2.0 e JWT (JSON Web Tokens) tornaram-se o padrão de facto para a construção de sistemas distribuídos. O OAuth 2.0 fornece um protocolo de acesso delegado, enquanto o JWT é um formato de token compacto e autossuficiente.
\nNeste artigo, com exemplos práticos em TypeScript, vamos analisar como implementar o ciclo completo de autorização: desde a emissão de tokens até sua validação e renovação. Você aprenderá como proteger endpoints de API, implementar refresh tokens e tratar erros típicos.
\n\n1. Configuração básica do projeto e instalação de dependências
\nPara começar, vamos criar um projeto em Node.js com TypeScript. Certifique-se de ter Node.js (versão 18+) e npm instalados.
mkdir oauth-jwt-typescript\ncd oauth-jwt-typescript\nnpm init -y\nnpm install express cors dotenv jsonwebtoken bcrypt\nnpm install -D typescript @types/express @types/cors @types/jsonwebtoken @types/bcrypt ts-node nodemon\nnpx tsc --init\nVamos configurar o tsconfig.json para trabalhar com módulos ES e tipos estritos. No arquivo .env, adicionaremos as chaves secretas:
ACCESS_TOKEN_SECRET=your-super-secret-access-key\nREFRESH_TOKEN_SECRET=your-super-secret-refresh-key\nACCESS_TOKEN_EXPIRES_IN=15m\nREFRESH_TOKEN_EXPIRES_IN=7d\n\n2. Implementação da geração e verificação de tokens JWT
\nVamos criar a utilitária src/utils/jwt.ts para trabalhar com tokens. Usaremos dois tipos de tokens: Access Token (de curta duração) e Refresh Token (de longa duração).
import jwt from 'jsonwebtoken';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\ninterface TokenPayload {\n userId: string;\n email: string;\n role: 'user' | 'admin';\n}\n\nexport const generateAccessToken = (payload: TokenPayload): string => {\n return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET!, {\n expiresIn: process.env.ACCESS_TOKEN_EXPIRES_IN || '15m',\n });\n};\n\nexport const generateRefreshToken = (payload: TokenPayload): string => {\n return jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET!, {\n expiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || '7d',\n });\n};\n\nexport const verifyAccessToken = (token: string): TokenPayload => {\n return jwt.verify(token, process.env.ACCESS_TOKEN_SECRET!) as TokenPayload;\n};\n\nexport const verifyRefreshToken = (token: string): TokenPayload => {\n return jwt.verify(token, process.env.REFRESH_TOKEN_SECRET!) as TokenPayload;\n};\nObserve: usamos tipagem estrita para o payload. Isso garante que o token sempre terá os campos necessários.
\n\n3. Criação de middleware para proteção de rotas
\nAgora vamos implementar o middleware que verificará a presença e validade do Access Token no cabeçalho Authorization. Crie src/middleware/auth.ts:
import { Request, Response, NextFunction } from 'express';\nimport { verifyAccessToken } from '../utils/jwt';\n\nexport interface AuthRequest extends Request {\n user?: {\n userId: string;\n email: string;\n role: 'user' | 'admin';\n };\n}\n\nexport const authenticate = (req: AuthRequest, res: Response, next: NextFunction): void => {\n const authHeader = req.headers['authorization'];\n const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN\n\n if (!token) {\n res.status(401).json({ error: 'Access token is required' });\n return;\n }\n\n try {\n const decoded = verifyAccessToken(token);\n req.user = decoded;\n next();\n } catch (error) {\n res.status(403).json({ error: 'Invalid or expired access token' });\n }\n};\n\nexport const authorizeRole = (...roles: string[]) => {\n return (req: AuthRequest, res: Response, next: NextFunction): void => {\n if (!req.user || !roles