3.4 KiB
3.4 KiB
Guia didatico: validar JWT nos servicos consumidores (sem JWKS)
Este guia mostra a forma mais simples de integrar os servicos:
- Auth assina o token com
JWT_PRIVATE_KEY_PEM - cada servico consumidor valida localmente com
JWT_PUBLIC_KEY_PEM
1) Configuracao em cada servico consumidor
Cada servico precisa ter no .env:
JWT_ISSUER="https://auth.local"
JWT_AUDIENCE="internal-apis"
JWT_PUBLIC_KEY_PEM="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
Importante:
- o
JWT_PUBLIC_KEY_PEMdeve ser exatamente a chave publica do Auth - mantenha os
\nliterais no.env
2) O que validar
Para toda rota protegida:
- ler
Authorization - extrair
Bearer <token> - validar assinatura RS256 com
JWT_PUBLIC_KEY_PEM - validar
iss,audeexp - validar se
subexiste - montar
request.auth = { id: sub, token }
Se algo falhar, retornar 401.
3) Exemplo pratico (Node/Express + jose)
import express from "express";
import { importSPKI, jwtVerify } from "jose";
const app = express();
const ISSUER = process.env.JWT_ISSUER!;
const AUDIENCE = process.env.JWT_AUDIENCE!;
const PUBLIC_KEY_PEM = process.env.JWT_PUBLIC_KEY_PEM!.replace(/\\n/g, "\n");
let publicKeyPromise: ReturnType<typeof importSPKI> | null = null;
function getPublicKey() {
if (!publicKeyPromise) {
publicKeyPromise = importSPKI(PUBLIC_KEY_PEM, "RS256");
}
return publicKeyPromise;
}
function authMiddleware() {
return async (req, res, next) => {
try {
const authHeader = req.header("authorization");
if (!authHeader) {
return res
.status(401)
.json({ message: "Missing Authorization header" });
}
const [scheme, token] = authHeader.split(" ");
if (!scheme || !token || scheme.toLowerCase() !== "bearer") {
return res
.status(401)
.json({ message: "Authorization must be Bearer token" });
}
const publicKey = await getPublicKey();
const { payload } = await jwtVerify(token, publicKey, {
issuer: ISSUER,
audience: AUDIENCE,
algorithms: ["RS256"],
});
if (typeof payload.sub !== "string" || !payload.sub.trim()) {
return res.status(401).json({ message: "Invalid token claims" });
}
req.auth = {
id: payload.sub,
token,
};
return next();
} catch {
return res
.status(401)
.json({ message: "Invalid or expired access token" });
}
};
}
app.get("/profile/me", authMiddleware(), (req, res) => {
return res.json({ userId: req.auth.id });
});
4) Propagacao entre servicos (A -> B)
Quando API A chamar API B em nome do usuario:
- repasse o mesmo
Authorization: Bearer <token> - API B valida esse token com
JWT_PUBLIC_KEY_PEM - API B usa
subcomo identidade confiavel
const authHeader = req.header("authorization");
const response = await fetch("http://courses-service/courses/me", {
headers: { Authorization: authHeader! },
});
5) Checklist rapido
- todos os servicos com o mesmo
JWT_PUBLIC_KEY_PEM - middleware valida assinatura +
iss+aud+exp subobrigatorio- retorna
401para token ausente/invalido/expirado - usa
subcomo ID confiavel
6) Trade-off dessa abordagem
Vantagem:
- muito simples para implementar e explicar
Desvantagem:
- quando trocar a chave publica, precisa atualizar o
.envde todos os servicos consumidores