diff --git a/docs/keycape-service-registrations.md b/docs/keycape-service-registrations.md index 6ac629f..87c4eec 100644 --- a/docs/keycape-service-registrations.md +++ b/docs/keycape-service-registrations.md @@ -117,3 +117,43 @@ clients: Human approvers use the existing KeyCape human flow with `approval:approve` only, still with `aud=approval-engine`. They must not receive `approval:consume`. + +## Human approver client — not supplied (2026-09-08) + +`KEY-WP-0013-T02` asked for two exact strings for the human approver +registration (public client, authorization code + S256 PKCE, exact redirect, +`aud=approval-engine`, `allowedScopes: [openid, approval:approve]`, +`mfaRequired: true`): the `client_id` and the full callback URI. + +**This repository cannot supply either, and must not guess one.** Redirects are +matched exactly at `/authorize`, so a fabricated value fails closed — or, worse, +registers a redirect no deployed component owns. + +Why there is nothing to give: + +- approval-engine is a bearer-token **resource server** only. `approval_engine/api.py` + is a WSGI app whose every non-health route reads `Authorization: Bearer …` + (`approval_engine/auth.py`). There is no `/callback`, no redirect handling, no + authorization-code or PKCE code anywhere in the package. +- Nothing here is a browser client. The requested registrations above are both + `client_credentials` confidential service clients. +- The service is not publicly addressable: `deploy/approval-engine.yaml` has a + Namespace, ClusterIP Service and StatefulSet — no Ingress, no external + hostname — so no `https://…/callback` origin exists to register. + +The human approver flow therefore belongs to whichever **browser-facing +approver UI** presents `approval:approve` tokens to this engine. That component +is not in this repo and is not named in `APPROVAL-WP-0002`. The two strings must +come from its owner once it exists and has a deployed origin; approval-engine +only needs the resulting access token to carry `aud=approval-engine`, +`principal_type: human`, `tenant: tenant:platform` and scope `approval:approve`. + +### Token confirmed: access token, never the ID token + +`ApiApplication.identity` verifies the **access token** presented as +`Authorization: Bearer` at this resource — RS256 against the deployed issuer's +`/jwks`, checking `iss`, `aud=approval-engine`, `exp`/`iat` (30s leeway), `sub`, +`principal_type`, `tenant` (exact equality with the store tenant), `roles`, +`scope` and `assurance`. `id_token` appears nowhere in the codebase; the ID +token belongs to the login client and is never evidence here. Human principals +are additionally refused `approval:consume`. diff --git a/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md b/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md index 25c93e0..2e9fad5 100644 --- a/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md +++ b/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md @@ -121,6 +121,22 @@ This resolves the choice of value only. T01 stays `progress`: KeyCape still has to own and prove these registrations, and credential materialization is unchanged. +2026-09-08 follow-up: key-cape (`KEY-WP-0013-T02`) asked for the human approver +client's exact `client_id` and full callback URI. Neither is supplied, and +neither is guessed: this engine is a bearer-token resource server with no +redirect endpoint, no authorization-code/PKCE code and no Ingress or external +origin (`deploy/approval-engine.yaml` is Namespace + ClusterIP + StatefulSet), +so no callback URI exists here to register — and redirects match exactly at +`/authorize`, so an invented value either fails closed or registers an origin no +component owns. The human browser client belongs to an approver UI that this +repo does not contain and `APPROVAL-WP-0002` does not name; the two strings must +come from that component's owner. Confirmed to key-cape in the same reply: this +resource validates the **access** token (`Authorization: Bearer`, RS256 via the +issuer's `/jwks`, checking `iss`, `aud=approval-engine`, expiry, `sub`, +`principal_type`, `tenant`, `roles`, `scope`, `assurance`); `id_token` appears +nowhere in the codebase. Recorded in `docs/keycape-service-registrations.md`. +T01 stays `progress`. + ## Harden durable storage and migrations ```task