# 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.