Assistant: codex Assistant-Model: gpt-5.6-luna Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
2.6 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. The two service registrations require
custody-managed values for the named environment references and a reviewed
rollout of this version, including the upstream issuer precondition. Platform's
CCR-2026-0017/0018 use OpenBao field CLIENT_SECRET; their approval remains open.
The separate human registration needs its actual UI-owned callback. A bearer-only
approval resource server has no such callback; its absence does not prevent
service-client issuance or service startup, and service credentials cannot be
counted as human approval evidence. 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.
Negative verification requires the token endpoint's typed refusal: HTTP 400,
invalid_profile_usage, feature scope for excess scope; HTTP 401 with feature
Authorization for a predecessor secret. A timeout, 5xx, malformed response,
invalid signature or JWKS failure is not proof of denial.
KeyCape owns issuance and client grants/disablement. OpenBao and the deployment operator own credential custody; approval-engine enforces its resource policy.