key-cape/docs/approval-engine-auth-contract.md
tegwick 403904b901
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 36s
Add bounded resource audiences and enforce browser scope grants
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a06e87-e039-7ed2-b85c-20ad37f8a21b
2026-09-05 00:41:17 +02:00

1.9 KiB

Approval-engine token contract

Static client registrations may set audience: approval-engine. This selects only the access-token audience; OIDC ID tokens retain aud=clientId. Omitting audience preserves the existing client-ID access audience, including OpenBao consumers. Request audience and resource parameters cannot override it. Access tokens contain the granted scope string for both supported grant types.

config/service-clients.example.yaml provides the two requested confidential clients: secrets-engine-approval gets read/consume, and approval-engine-operator gets lifecycle/observation scopes without consume. Service tokens contain principal_type=service, tenant, roles, scope, assurance, issuer, subject, audience, issue time and expiry; the lifetime is 15 minutes. The issuer signs with RS256 and publishes its public key through /jwks.

Human approvers need a separate authorization-code/PKCE registration with an exact deployment-owned callback, audience: approval-engine, allowedScopes: [openid, approval:approve], and mfaRequired: true. Do not add consume or other approval grants to that client. No callback is invented here. The ID token is for the login client; present the access token to approval-engine.

These fragments are not live registrations. Deployment requires custody-managed values for the named environment references, the exact human callback, and a rollout of this version. Never log the token or secret. Verify the resulting access token against the deployed issuer's /jwks, checking issuer, audience, expiry, subject, principal type, tenant, roles, scope and assurance. Verify that operator consume and human consume requests are rejected. Local tests verify signatures against the JWKS handler; they do not constitute live issuance proof.

KeyCape owns issuance and client grants/disablement. OpenBao and the deployment operator own credential custody; approval-engine enforces its resource policy.