Problema
JWT com payload gigante, role: admin sem checagem por rota, refresh token sem rotação e logout “fake”. RBAC vira string solta no código (if (user.role === 'x')) espalhada em dezenas de handlers.
Solução
Separar autenticação (quem é) de autorização (o que pode). Access token curto; refresh com rotação e armazenamento revogável. RBAC com matriz recurso × ação ou policies; guard/middleware único que interpreta claims + regras.
Arquitetura
Login → emite access (15m) + refresh (httpOnly cookie ou device-bound)
API → valida JWT + carrega permissions (cache) → Authorize("invoice:read")
- Preferir permissions estáveis a roles crescentes (
admin2,superadmin). - Para multi-tenant:
tenantIdno token + RLS no DB ou filtro obrigatório no repositório.
Código
// guard conceitual
function requirePermission(perm: string) {
return (req: AuthedRequest, res: Response, next: NextFunction) => {
if (!req.auth.permissions.has(perm)) {
return res.status(403).json({ error: "Forbidden" });
}
next();
};
}
router.get(
"/invoices/:id",
authMiddleware,
requirePermission("invoice:read"),
getInvoice
);Performance
Cache de JWKS; introspecção mínima; não ir ao DB em toda request se claims forem suficientes — mas invalidação exige estratégia (TTL curto ou version de session).
Melhorias futuras
OAuth2/OIDC corporativo; ABAC para regras finas; auditoria de negações.
Conclusão
JWT bem usado é estado mínimo assinado; RBAC bem usado é política centralizada. Isso conversa direto com vagas full stack e backend sênior.