Approval Workflow (AWE) integration
How the Consent Manager integrates the shared Approval Workflow Engine (AWE) to gate data-share policy changes behind human approval, with approvers acting in CM's own UI.
The Consent Manager (CM) integrates the shared Approval Workflow Engine (AWE) to gate data-share policy changes behind configurable, multi-stage human approval. Widening a partner's policy — granting more scopes, purposes, subject-id types, signing algs, or longer validity / data_life — does not take effect until AWE delivers an approved outcome. CM acts as a caller service: it submits requests, proxies approver task interactions on behalf of its own users, and reacts to terminal outcomes via a webhook.
This integration governs policy changes only. Partner identity, keys, and onboarding live in the Partner Management service (see Partner Management Integration) — AWE does not gate partner onboarding in CM.
Deployment note: AWE is installed once per environment (part of commons-services), not bundled with each CM. CM points awe_base_url at the environment's AWE and registers its own per-CM callback secret into the shared AWE database out-of-band. Because callbacks are addressed per request (each caller passes its own callback URL and callback_secret_id), one shared AWE serves the registry, SPAR, CM, and other callers in the same environment.
Two distinct "policies"
The word policy means two different things here — do not conflate them:
CM data-share policy
The artefact / rules: allowed_data_scopes, purposes, subject-id types, signing algs, validity, fetch semantics, data_life. Versioned per partner binding.
CM (PartnerPolicy)
AWE approval policy (policy_key)
The workflow: stages, approvers, SLA, delegation.
AWE
A change to the CM data-share policy is the artifact that is routed through an AWE approval policy (the workflow). CM references the approval policy by its policy_key.
End-to-end flow
Widen — an admin upserts a policy that grants more than the current active version (the first policy also counts as widening). CM creates a new
PartnerPolicyversion in statuspending. The prior active version stays in force — the hot path is unaffected.Submit to AWE — CM (using a service token) calls
POST {awe_base_url}/v1/awe/requestswithpolicy_key=<AWE approval policy>,artifact_type=consent_manager.policy_change,artifact_id=<policy version id>, a context snapshot (partner label, controller, and the scope/purpose diff), and a callback URL. AWE returns arequest_id, which CM stores on the pending version.Approver acts in CM's UI — approvers use CM's own approver inbox, never AWE's UI. CM proxies AWE's task-list and decision calls, forwarding the approver's own Keycloak JWT so AWE's
sub-based task ownership works.Terminal webhook — when the workflow completes, AWE POSTs a terminal event to CM's callback URL:
request_approved→ the pending version becomesactiveand supersedes the prior version.request_rejected/request_cancelled→ the version is markedrejected; the prior active version remains in force.
A pure narrowing change, or an environment with AWE disabled, skips steps 2–4 and activates immediately.
Two token types
CM talks to AWE with two different tokens depending on the call:
Service token (client-credentials)
create_request — submitting the policy change to AWE.
Approver's own JWT (forwarded unchanged)
All proxied approver calls: list my tasks, submit decision, claim a task, get a request + its events.
The approver's bearer is extracted at the HTTP layer and passed through untouched so AWE resolves task ownership by the approver's sub.
Approver proxy & inbox
AWE ships only an /admin operator UI — it has no approver UI. CM therefore exposes an approver inbox in its own console and proxies the approver-facing AWE calls under /consent/v1/awe/… (plain REST):
GET /consent/v1/awe/tasks
GET /v1/awe/tasks?assignee=me
approver JWT
POST /consent/v1/awe/tasks/{id}/decision
submit decision
approver JWT
POST /consent/v1/awe/tasks/{id}/claim
claim task
approver JWT
GET /consent/v1/awe/requests/{id}
get request
approver JWT
GET /consent/v1/awe/requests/{id}/events
get request events
approver JWT
The proxy routes are gated on the CM approver role (CONSENT_MANAGER_APPROVER). The context sent on create_request carries business-meaning fields (partner label, controller, policy version, scope/purpose diff) so the inbox can render a meaningful task, not just an opaque artifact id.
Inbound webhook (HMAC)
The terminal callback from AWE is HMAC-only — no bearer token. AWE signs the request:
CM verifies the signature against the raw request bytes, rejects stale timestamps (outside the allowed skew), and deduplicates by event id so a redelivered webhook is idempotent. The per-caller callback secret is registered into the shared AWE database out-of-band and looked up by callback_secret_id; CM holds the same raw secret to verify. Terminal events: request_approved, request_rejected, request_cancelled.
Configuration
AWE integration is off by default (consent_manager_awe_enabled = false → policy changes activate immediately, legacy behaviour). Relevant keys:
consent_manager_awe_enabled
Master switch. When false, all policy changes activate immediately.
awe_base_url
Base URL of the environment's shared AWE.
awe_policy_change_policy_key
The AWE approval policy_key (workflow) used for policy-change requests.
awe_callback_url
The URL AWE POSTs terminal webhooks to (in-cluster CM API + /consent/v1/awe/webhooks/decision).
awe_callback_secret_id / awe_callback_hmac_secret
The callback_secret_id AWE looks up, and the raw HMAC secret CM verifies with.
awe_client_id / awe_client_secret (or a static token)
Client-credentials creds for the service token used on create_request.
auth_approver_role
The CM role that gates the approver inbox / proxy routes (CONSENT_MANAGER_APPROVER).
Enabling AWE approval — required AWE-side setup
AWE approval is an optional add-on. CM is fully usable with it off (policy changes just take effect immediately, still admin-only). Turning it on (global.aweEnabled: true) needs setup that CM does not auto-provision — only the callback secret + callback URL are wired automatically:
Register the approval policy in AWE for
awe_policy_change_policy_key(consent-manager.policy_change.v1). AWE policies are created as a draft and then activated (both require anAWE_ADMINtoken). A minimal single-stage, role-based policy:Adjust the stage(s)/rules to your governance (roles, groups, quorum, multi-stage). Without an active policy for this key,
create_requestreturns 404 and CM leaves the wideningpendingwith no AWE request id.Designate approvers — users the policy's rule resolves (here, anyone with the
CONSENT_MANAGER_APPROVERrole), who also need that role to open CM's approvals inbox.Token issuer alignment — the
consent-managerclient's token (used forcreate_request) must be issued by the issuer AWE trusts (AWE'skeycloak.issuer). A mismatch surfaces as AWE rejecting the call withInvalid issuer; make sure CM'sawe_token_urland AWE's configured issuer resolve to the same Keycloak realm URL.
The sanity e2e is AWE-aware: with approval on, its first (widening) policy goes
pending, so the signed permit round-trip is skipped (it can't complete without a human approval) — smoke + contract still run.
Related pages
Partner policy binding & approval — the policy model and what "widening" means.
Architecture — the PDP/PEP model and where the policy engine sits.
Approval Workflow Engine (AWE) — AWE functional specs, API reference, and deployment guide.
Last updated
Was this helpful?