Gateway — access token Microsoft Entra (Modo B)
Guia para DevOps e clientes que exigem Access Token Entra (aud = api://{app-id}) no API Gateway, em vez do JWT ECOSIF (Modo A).
Código tarefa: AUTH-09 · P7-06
Público: administradores Entra ID, DevOps, arquitetos de integração
Pré-requisitos: App Registration com API exposta (ver runbook Azure Entra §3)
Quando usar
| Cenário | Modo |
|---|---|
| Gateway interno (Traefik) com secret compartilhado | A — ECOSIF_JWT + gateway_jwt_ecosif.md |
| Cliente com Azure API Management, ALB ou WAF que só aceita token Microsoft | B — AZURE_ENTERPRISE_GATEWAY |
Regra: ECOSIF_API_TOKEN_MODE e ECOSIF_AUTH_PROVIDER devem estar alinhados em Angular, backends e gateway.
Visão geral do fluxo
Login (uma vez)
Angular/MSAL popup → id_token
→ POST /api/auth/external-login { provider: "AZURE_ENTERPRISE", token: "<id_token>" }
→ ecosif-auth valida id_token, provisiona gr_user + identity_provider_link
→ resposta { accessToken: <JWT_ECOSIF> } ← sessão/guard Angular apenas
APIs de negócio (cada requisição)
Angular acquireTokenSilent → access_token (aud = api://{client-id})
→ Authorization: Bearer <access_token>
→ API Gateway valida JWKS Entra (aud, iss, exp)
→ microsserviço valida o mesmo token (OAuth2 Resource Server)
→ resolve usuário: claim oid/sub → identity_provider_link → gr_user
Dois tokens Microsoft coexistem:
| Token | Onde | aud típico |
Validador |
|---|---|---|---|
| ID Token | POST /api/auth/external-login |
Client ID (SPA) | ecosif-auth (JWKS) |
| Access Token | Authorization em /ecosif-* |
api://{client-id} |
Gateway + backends |
O JWT ECOSIF não trafega nas APIs de negócio no Modo B.
Variáveis de ambiente
Stack completa (compose / ECS)
# Modo B — obrigatório alinhar em todos os serviços + Angular
ECOSIF_API_TOKEN_MODE=AZURE_ENTERPRISE_GATEWAY
ECOSIF_AUTH_PROVIDER=AZURE_ENTERPRISE
# Gateway — documentação/ops (≤32 chars)
ECOSIF_GWVAL_JWT_ECOSIF=false
ECOSIF_GWVAL_ACCESSTOKEN_MS=true
# Entra — mesmos valores do runbook Azure
ECOSIF_AZURE_CLIENT_ID=<application-client-id>
ECOSIF_AZURE_TENANT_ID=<directory-tenant-id>
ECOSIF_AZURE_AUTHORITY=https://login.microsoftonline.com/<tenant-id>
ECOSIF_AZURE_SCOPES=openid,profile,email,api://<client-id>/access_as_user
ECOSIF_AZURE_API_AUDIENCE=api://<client-id>
# Angular
ECOSIF_ENABLE_AZURE_AUTH=true
ECOSIF_ENABLE_LOCAL_AUTH=false # típico em SSO obrigatório
Backends Java (application.yml → ecosif.security.*)
| Propriedade | Variável | Descrição |
|---|---|---|
ecosif.security.api-token-mode |
ECOSIF_API_TOKEN_MODE |
AZURE_ENTERPRISE_GATEWAY |
ecosif.security.auth-provider |
ECOSIF_AUTH_PROVIDER |
AZURE_ENTERPRISE |
ecosif.security.azure.tenant-id |
ECOSIF_AZURE_TENANT_ID |
Tenant para JWKS/issuer |
ecosif.security.azure.api-audience |
ECOSIF_AZURE_API_AUDIENCE |
aud esperado no access token |
Microsserviços afetados: ecosif-auth, ecosif-masterdata, ecosif-moviments, ecosif-querys, ecosif-reports.
Validação no gateway
Parâmetros JWT (access token)
| Claim / parâmetro | Valor |
|---|---|
| Algoritmo | RS256 |
| JWKS | https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys |
Issuer (iss) |
https://login.microsoftonline.com/{tenant-id}/v2.0 |
Audience (aud) |
api://{client-id} (= ECOSIF_AZURE_API_AUDIENCE) |
| Identidade | oid (preferencial) ou sub → mapeamento no backend |
Rotas públicas (sem access token)
POST */api/auth/external-loginPOST */api/auth/signin(seECOSIF_ENABLE_LOCAL_AUTH=true)GET */actuator/health*- Assets do Angular (
/,/assets/*)
Rotas protegidas
Todas as demais sob /ecosif-* exigem Authorization: Bearer <access_token> válido.
Defense in depth: o gateway e cada microsserviço validam o token. Não confiar apenas na borda.
Azure API Management (referência)
JWT validate policy (HTTP API inbound)
Substitua {tenant-id} e {client-id}:
<inbound>
<validate-jwt header-name="Authorization" failed-validation-httpcode="401"
failed-validation-error-message="Token Microsoft inválido">
<openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
<audiences>
<audience>api://{client-id}</audience>
</audiences>
<issuers>
<issuer>https://login.microsoftonline.com/{tenant-id}/v2.0</issuer>
</issuers>
</validate-jwt>
<base />
</inbound>
Exceções no APIM
Configure operation policies sem validate-jwt para:
POST /ecosif-auth/api/auth/external-loginPOST /ecosif-auth/api/auth/signin(se login local habilitado)
AWS API Gateway (HTTP API)
- Criar JWT Authorizer:
- Issuer:
https://login.microsoftonline.com/{tenant-id}/v2.0- Audience:api://{client-id}- O API Gateway resolve JWKS automaticamente a partir do issuer. - Associar o authorizer às rotas
/ecosif-*. - Não associar a
POST /ecosif-auth/api/auth/external-loginnemsignin. - Para rotas mistas (Modo A + B em ambientes diferentes), use APIs/stages separados — não misturar HS256 e RS256 no mesmo authorizer.
Traefik (referência)
Com plugin JWT/OIDC (ex.: traefik-plugin-jwt ou middleware custom):
| Parâmetro | Valor |
|---|---|
jwksUrl |
https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys |
issuer |
https://login.microsoftonline.com/{tenant-id}/v2.0 |
audience |
api://{client-id} |
Rotas de login e health ficam fora do middleware JWT.
Frontend (Angular)
| Componente | Comportamento Modo B |
|---|---|
login.component.ts |
MSAL popup → external-login com id_token |
api-token-provider.service.ts |
acquireTokenSilent com scopes de ECOSIF_AZURE_SCOPES |
auth.interceptor.ts |
Envia access_token MSAL; sem refresh via GET /user |
Sessão / AuthGuard |
JWT ECOSIF em localStorage após external-login (bootstrap UI) |
Guia frontend: configuracao_provedores.md — Perfil 4.
Checklist de homologação
- [ ] App Registration com Expose an API + scope
access_as_user+ admin consent - [ ]
ECOSIF_API_TOKEN_MODE=AZURE_ENTERPRISE_GATEWAYem Angular + 5 backends - [ ]
ECOSIF_GWVAL_ACCESSTOKEN_MS=trueeECOSIF_GWVAL_JWT_ECOSIF=falsedocumentados no gateway - [ ] Login Microsoft →
external-loginretorna 200 + JWT ECOSIF (sessão) - [ ] Chamada
GET /ecosif-masterdata/...com access token → 200 - [ ] Mesma chamada com JWT ECOSIF → 401 no gateway ou backend
- [ ] Token expirado → 401; MSAL renova via
acquireTokenSilent - [ ]
oid/subdo token existe emidentity_provider_linkapós primeiro login
Verificação no browser (DevTools → Network)
external-login: body com id_token; resposta com JWT ECOSIF- APIs
/ecosif-*: headerAuthorization: Bearer eyJ...comaud=api://...(decodificar em jwt.ms)
Troubleshooting
| Sintoma | Causa provável | Ação |
|---|---|---|
| 401 em todas as APIs após login OK | aud divergente |
Conferir ECOSIF_AZURE_API_AUDIENCE = Application ID URI |
acquireTokenSilent falha |
Scope/consent | Admin consent em access_as_user; scopes no Angular |
| 401 só no backend, gateway OK | Backend em Modo A | ECOSIF_API_TOKEN_MODE no container Java |
| Usuário não encontrado (403) | Sem link | Verificar identity_provider_link após external-login |
401 em external-login |
Token errado | Enviar id_token, não access token |
Referências
| Documento | Conteúdo |
|---|---|
| gateway_jwt_ecosif.md | Modo A — JWT ECOSIF |
| gateway_access_token_google.md | Modo C — Google |
| variaveis_autenticacao_baseline.md | Catálogo ECOSIF_* |
| runbook_azure_entra.md | App Registration Entra |
| configuracao_provedores.md | Angular Modo B |
| mvp5_integracao_avancada.md | Fase 7 / AUTH-09 |