CommBank ID + income

Architecture

How the pieces fit

Six participants, one event stream and a pod per customer. The diagrams are rendered from Mermaid sources in apps/microsite/diagrams/.

System view

The thick path is the renter's journey. Dotted lines are asynchronous or trust relationships. The CDR leg sits entirely inside Ping CDR Kit stacks - CommBank's data-in stack on one side, a full data holder stack per bank on the other, and the kit's Register test harness anchoring trust.

system diagram
Mermaid source · full size

Participant isolation

No two participants share a Docker network. Cross-participant calls go through published ports, exactly as they would between Railway services - so the local and hosted topologies match.

Tokens never leave the kit

The pod asks the kit PingAccess for data with its own client-credentials token and an X-CDR-Subject header. The kit rule finds the arrangement, refreshes the bank token if due, and swaps it in.

Events from Ping, not app code

PingDataSync is the kit's own way of reacting to token-store changes. A Server SDK sync destination publishes to Redis, with durable, resumable delivery from the changelog.

Trust model

This is the kit's trust profile, unchanged. The Register signs CommBank's software statement assertion and issues every participant's certificate from its CA.

trust diagram
Mermaid source · full size
Register SSAPS256, iss=cdr-register, signed with key _GLOBAL_. Its jwks_uri points at the kit PF's /pf/JWKS - CommBank's software product key.
DCRPOST {issuer}/register, application/jwt signed with the software product key and carrying the SSA, over mTLS with a Register-CA client certificate. The kit issues client_id = dcr-sso-<nameUUIDFromBytes(software_id)> and allows one registration per software id.
mTLSPingAccess at each data holder requires the client certificate. Tokens are certificate-bound (cnf.x5t#S256), so every token, API and revocation call must present the same certificate.
private_key_jwtClient assertions with header typ: client-authentication+jwt (PF 13 rejects JWT), aud = the DH issuer.
PAR/as/par.oauth2 with a PS256 request object carrying claims.sharing_duration and claims.id_token.acr, PKCE S256. response_type=code id_token, the id_token encrypted RSA-OAEP / A256GCM.
RevocationADR → DH: POST {issuer}/data-holder/arrangements/revoke with a client assertion over mTLS. DH → ADR: the kit servlet at /arrangements/revoke checks a DH-signed bearer JWT against the DH JWKS from the Register.

Async pod creation

Nothing calls the pod directly after consent. The kit's token store changes, PingDataSync notices, and an event on cdr.arrangements does the rest. The consumer acks only once the arrangement is in the pod's manifest; failures retry with back-off and poison messages go to a dead-letter stream.

seq-pod diagram
Mermaid source · full size

Issuance

MATTR has no issuer_state on auth-code offers, so the binding that holds is the CBA PingFederate sub flowing into the claim source. The claim source merges identity with the pod's income output, with the purpose credential-issuance checked against the customer's use consents.

seq-issuance diagram
Mermaid source · full size

Proof verification

The proof says one thing - income is at least the threshold - and the pod's signature ties it to the same commitment that sits in the credential. The verifier checks the Groth16 proof on the server and again in the browser.

seq-proof diagram
Mermaid source · full size

Deletion lifecycle

A pod can't outlive the consent that created it. The sweep runs every 15 seconds; once-off consents keep income for a short window (10 minutes in the demo) after it's ready, so the customer can claim the credential and make proofs, then the data goes.

state-lifecycle diagram
Mermaid source · full size

CDR Data Pod internals

Every program runs through runProgram, which checks eligibility first: the arrangement is active, the consent type allows it, and every required scope and use consent is present. A refusal is audited and comes back as 403.

pod-internals diagram
Mermaid source · full size
ProgramNeeds scopesNeeds use consentWhat it does
token-manager--Client-credentials token from the kit PF for the kit PingAccess. Lives on one call stack, never stored or logged.
loaderaccounts.basic, transactions-Accounts → balances → 365 days of transactions, one step event per stage.
refresheraccounts.basic, transactions-Ongoing consents only. Unattended refresh within a daily call budget, then income again.
income-aggregatortransactionsincome-verificationGroups credits by payer, finds the cadence, drops outliers, scores confidence, annualises net pay.
zkp-provertransactionsincome-proofPoseidon commitment, Groth16 proof of income ≥ threshold, ES256 JWS over the commitment.
retention / destroyer--Deletes compartments on revoke, expiry or purpose fulfilled; destroys the pod and shreds its key.