Skip to main content

The four-signature trail

Every OID4AC charge produces four signed artefacts. Each is signed by a different party, covers a different scope, and binds to the others by hash. Reconstructing a charge from these four signatures is deterministic; missing any one signature collapses the chain.

Signature 1: Signed Offer (merchant -> agent)

The merchant publishes Offer JSON-LD at a stable URL (typically /products/{sku}). The body is signed with an RFC 9421 HTTP message signature over @method, @target-uri, @authority, content-type, and content-digest. The signature commits the merchant to the SKU, the price (amount_minor), and the currency at a specific URL within a 300-second window.

FieldDetail
SignerMerchant (private key registered in their JWKS)
SpecRFC 9421 HTTP message signature
Algorithmed25519 default, ecdsa-p256-sha256 fallback
Commits toSKU, price, currency, offer URL, content digest
TTLexpires - created in (0s, 300s]

Signature 2: JWT-AT (AS -> agent)

The agent posts a PAR request to the AS citing the offer digest. After consent at the Wallet Portal, the AS returns a JWT Access Token with typ=at+jwt, signed with the AS's Ed25519 signing key, and bound to the agent's DPoP key via cnf.jkt. The token commits the AS to: this agent acted on behalf of this principal, with this mandate, for this audience, for the next 300 seconds.

FieldDetail
SignerAuthorization Server (Ed25519 signing key)
SpecRFC 9068 JWT-AT claim set
AlgorithmEdDSA
Commits tosub (principal), aud (merchant), client_id (agent), cnf.jkt, mandate_id
TTL300 s

Signature 3: SD-JWT VC mandate (AS -> wallet -> merchant)

The AS issues an SD-JWT Verifiable Credential at consent time. The mandate carries the principal's spend cap, currency, merchant allowlist, and validity window in disclosable form. The wallet stores it; the agent retrieves it; the merchant verifies it against the AS JWKS at charge time. Selective disclosure lets the agent reveal only the fields the merchant needs.

FieldDetail
SignerAuthorization Server (Ed25519 signing key)
Specdraft-ietf-oauth-sd-jwt-vc
AlgorithmEdDSA
Commits toprincipal_id, spend_cap_minor, currency, merchant_allowlist, not_before, not_after
TTLUp to the mandate's not_after claim (typical: 24 h to 30 d)

Signature 4: KB-JWT presentation (agent -> merchant)

At charge time the agent mints a Key Binding JWT signed by the same DPoP keypair whose thumbprint is in the JWT-AT's cnf.jkt claim. The KB-JWT binds this presentation to this merchant audience and a single-use nonce of the form sha256(merchant_nonce || offer_digest). Replay across merchants or against a different offer is impossible.

FieldDetail
SignerAgent (DPoP keypair)
Specdraft-ietf-oauth-sd-jwt-vc §4.3 (Key Binding JWT)
AlgorithmEdDSA or ES256
Commits toaud (merchant origin), nonce (one-shot), iat
TTL60-second window

The chain

merchant agent wallet authorization server | | | | |--- signed Offer --> | | | (RFC 9421) | | | | |--- PAR (offer_digest) ------------------->| | | | 201 request_uri | | |--- authorize ---->|--- consent screen --->| | | | 302 code+iss | | |--- token -------------------------------->| | | JWT-AT (typ=at+jwt, cnf.jkt) + | | | SD-JWT VC mandate | | | | | |<-- KB-JWT presentation + mandate ----| | | | | | |--- verify (mandate, KB-JWT, JWT-AT) -------------------------| | | |--- charge (mandate_id, offer_digest, JWT-AT, DPoP proof) --->| | | |<-- payment_intent_id + audit chain entry --------------------|

Dispute reconstruction

Given the four signatures plus the audit chain entry, a dispute resolver can independently prove every causal link:

  1. Was the price what the merchant published? Verify signature 1 against the merchant's JWKS at the time of the dispute (JWKS history is retained for this lookup).
  2. Did the agent have authorisation? Verify signature 2 against the AS JWKS for that kid.
  3. Did the principal consent to this kind of spend? Verify signature 3 (the mandate VC) and check the spend_cap_minor vs the charge amount.
  4. Was this charge a fresh act, not a replay? Verify signature 4's nonce against the merchant's nonce log and the offer digest.
  5. Did this happen at the time the merchant claims? Verify the audit-chain entry's seq and prev_hash against the hourly-signed chain head.

A documented dispute-evidence procedure describes how to assemble the four signatures and the audit-chain entry into a single verifiable evidence pack.