# Guia didatico: validar JWT nos servicos consumidores (sem JWKS) Este guia mostra a forma mais simples de integrar os servicos: 1. Auth assina o token com `JWT_PRIVATE_KEY_PEM` 2. cada servico consumidor valida localmente com `JWT_PUBLIC_KEY_PEM` ## 1) Configuracao em cada servico consumidor Cada servico precisa ter no `.env`: ```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_PEM` deve ser exatamente a chave publica do Auth - mantenha os `\n` literais no `.env` ## 2) O que validar Para toda rota protegida: 1. ler `Authorization` 2. extrair `Bearer ` 3. validar assinatura RS256 com `JWT_PUBLIC_KEY_PEM` 4. validar `iss`, `aud` e `exp` 5. validar se `sub` existe 6. montar `request.auth = { id: sub, token }` Se algo falhar, retornar `401`. ## 3) Exemplo pratico (Node/Express + jose) ```ts 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 | 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 ` - API B valida esse token com `JWT_PUBLIC_KEY_PEM` - API B usa `sub` como identidade confiavel ```ts 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` - `sub` obrigatorio - retorna `401` para token ausente/invalido/expirado - usa `sub` como ID confiavel ## 6) Trade-off dessa abordagem Vantagem: - muito simples para implementar e explicar Desvantagem: - quando trocar a chave publica, precisa atualizar o `.env` de todos os servicos consumidores