feat: Web Bot Auth (WBA) interop #483
Open
igrigorik wants to merge 3 commits into
Open
Conversation
Extend the UCP signing-key JWK schema and signature spec to recognize EdDSA (Ed25519) keys per RFC 8037, alongside the existing ECDSA P-256/P-384 support. ECDSA P-256 (ES256) remains the universal UCP baseline. EdDSA is OPTIONAL for general UCP verifiers, with one specific implication: verifiers that opt into Web Bot Auth (WBA) interop MUST support EdDSA because WBA mandates Ed25519. Adding EdDSA as a recognized UCP algorithm is the necessary substrate for that interop path. Why --- UCP today supports ECDSA only. Web Bot Auth standardizes on Ed25519 for HTTP transport identity. UCP signers wanting interop with WBA verifiers cannot do so under an ECDSA-only UCP. This commit makes Ed25519 a recognized UCP algorithm so it can be used; the WBA opt-in story that uses it lands in subsequent commits. This change is purely additive: * ES256 verification remains a MUST (unchanged universal baseline). * ES384 remains OPTIONAL (unchanged). * EdDSA (Ed25519) is added as OPTIONAL for general verifiers; signers MAY use either algorithm and MAY publish keys of either type. * The profile schema's jwk_public_key definition is split into EC and OKP shapes via oneOf, matching standard JWK conventions. Verifier expectations --------------------- * A general UCP verifier MAY implement ES256-only. Existing deployments need not upgrade for this commit's purposes. * A verifier that wants to verify Web Bot Auth-compatible signatures MUST support EdDSA — that's a consequence of opting into WBA, not a UCP-imposed cost. Signer guidance --------------- * For maximum interoperability with UCP verifiers today: use ES256. * For WBA interop: use Ed25519 and coordinate counterparty support, or publish both algorithms and select per request. A merchant participating in both UCP HTTP transport (with WBA interop) and AP2 mandate signing today operates two keys: Ed25519 for HTTP transport, ECDSA P-256 for the AP2 merchant_authorization JWS (which AP2 v0.2 currently requires to be non-deterministic). Both keys live in the same signing_keys[] array and are selected by kid. If AP2 relaxes its algorithm rule in a future revision (tracked in AP2 #268, google-agentic-commerce/AP2#268), the merchant MAY collapse to a single Ed25519 key serving both layers; the wire format does not change. UCP-only sites that do not interact with WBA or AP2 may operate a single ES256 key (the universal baseline) and ignore EdDSA entirely. Schema ------ The jwk_public_key definition uses oneOf to enforce kty/crv consistency: * kty="EC" requires crv in {P-256, P-384} plus x and y coordinates. * kty="OKP" requires crv="Ed25519" plus x (single public key value). Private key material (d, p, q, dp, dq, qi, oth, k) remains explicitly forbidden via the existing "not" guard.
A UCP integrator MAY opt their primary signature into a Web Bot Auth- compatible shape, so the same RFC 9421 signature verifies under both UCP and WBA verifiers with one key and one signing operation. Existing UCP-only signers and verifiers change nothing. What's added ------------ signatures.md gains a new §WBA Interop subsection describing the opt-in: - Algorithm SHOULD be Ed25519 (WBA convention). - Signer MUST emit a Signature-Agent header alongside UCP-Agent. An RFC 8941 Dictionary Structured Field whose member's sf-string is an HTTPS URL pointing to a key directory; the member key matches the Signature-Input signature label. - Signer MUST sign the signature-agent component with ;key="<label>" matching the Signature-Agent member key (RFC 9421 §2.1.2 Dictionary-member component selection). - keyid MUST be the JWK SHA-256 Thumbprint (RFC 7638; RFC 8037 §2 for OKP). - created, expires, tag="web-bot-auth" MUST be in @signature-params. - The data: URI inline JWKS form is out of scope; Signature-Agent MUST carry an HTTPS URL. UCP's existing signed components (ucp-agent, idempotency-key, content-digest, content-type) stay in the signed list — WBA accepts them as "additional components" per the architecture draft §4.2.3. §REST Binding adds: - Signature-Agent header row to the headers table (conditional on WBA opt-in). - signature-agent;key= row to the REST Request Signing components table. - Signature-Agent parsing rules subsection in §REST Request Verification, with the dictionary-member-by-label-match rule. A complete WBA-shape request example shows one Ed25519 signature covering both regimes' required bytes. overview.md §Identity & Authentication picks up a short note about the Signature-Agent header pointing to the signatures.md opt-in. Why --- UCP integrators wanting interop with WBA-conformant verifiers previously needed two keys, two signatures per request, or to skip interop entirely. WBA's architecture draft §4.2.3 explicitly permits additional components beyond the WBA-required set, which makes a single-signature dual-audience shape valid under both regimes. Backwards compatibility ----------------------- Fully additive. UCP-only signers and verifiers continue to operate unchanged. WBA opt-in is per-signature; UCP verifiers built only for UCP-default signatures may need to add RFC 9421 §2.1.2 Dictionary- member component selection support to verify WBA-shape signatures (this is part of being RFC 9421-conformant, not WBA-specific).
Add a top-level keys[] field to the UCP profile schema (RFC 7517 JWK Set), making a UCP profile a valid JSON Web Key Set. This enables one document to serve as both a UCP profile and a Web Bot Auth-compatible key directory at the same URL. Document deployment patterns and the verifier's identity-resolution algorithm. What's added ------------ source/schemas/profile.json: - New top-level keys[] property, sibling to signing_keys[] and ucp. - signing_keys[] stays canonical (every UCP verifier reads it). Description updated to point profiles toward keys[] as the optional JWKS-superset mirror for WBA-directory compatibility. - When both arrays are published, they MUST list the same set of kid values, and entries sharing a kid MUST be semantically equivalent (identical RFC 7638 thumbprints; serialization differences not significant). - EC alg/crv coupling: ES256 with P-256, ES384 with P-384 enforced via if/then in the EC oneOf branch. overview.md: - §Profile Structure: the keys[] mirror, the RFC 7517 §5 "additional members" allowance, and the cross-array equivalence rule. - Business Profile example now publishes both arrays as semantic mirrors, with an Ed25519 key (HTTP transport identity) and an ECDSA P-256 key (AP2 mandate JWT) demonstrating UCP+WBA+AP2 composition. - §Identity & Authentication: tag-driven dispatch language. Sites opting into WBA interop emit both UCP-Agent (capability discovery + default-UCP key lookup) and Signature-Agent (WBA-shape key lookup). - §Key Discovery: regime-aware lookup table (default UCP → signing_keys[]; WBA-shape → keys[]). - New §Deployment Patterns for WBA Interop subsection: Pattern 1 (content negotiation, one URL, two media types); Pattern 2 (two URLs, isolated signing complexity). WBA Response Signing deferred to draft-meunier-http-message-signatures-directory §5.2 with operational guidance on authority-keyed caching. - New §Identity Resolution Algorithm subsection: per-signature dispatch on the tag parameter (tag="web-bot-auth" → resolve via Signature-Agent; no/other tag → resolve via UCP-Agent; unknown tag → skip). Explicit skip semantics for missing Signature-Agent header, fetch failure, non-HTTPS URL, no keyid match, and signed-components mismatch. SHOULD-level keyid↔JWK-thumbprint check for WBA-shape signatures. Authenticated transport-identity rule, with explicit scoping that payload-layer assertions (e.g., AP2 mandate JWTs) follow their own identity binding. signatures.md: - Architecture diagram updated for keys[] / signing_keys[] dual publishing. - §Key Discovery defers publishing contract to overview.md §Profile Structure (regime-aware lookup table only). Backwards compatibility ----------------------- Fully additive. Profiles publishing only signing_keys[] (the canonical field) remain valid. Profiles wanting WBA-directory compatibility add keys[] as a mirror; the two-array dual-publish keeps every existing UCP verifier working unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
UCP specifies RFC 9421 message signatures. But there are incompatible restrictions and missing guidance for a well-implemented Web Both Auth (WBA) deployment and interop:
signing_keys[]; WBA verifiers read RFC 7517keys[]. UCP didn't forbid addingkeys[]to the profile but didn't define its role either — an integrator publishing both arrays had no normative guidance on which was authoritative.UCP-Agentpoints to the UCP profile;Signature-Agentpoints to a WBA key directory. An integrator could emit both, but UCP didn't define what they meant relative to each other or how verifiers should pick between them.An integrator could try to compose UCP + WBA on their own, but the algorithm restriction was a hard block, and the semantic gaps meant any composition was bespoke and likely to drift across implementations.
This PR resolves all three. WBA's architecture draft §4.2.3 explicitly permits additional components beyond the WBA-required set, which makes a single-signature dual-audience shape valid under both regimes once the algorithm is supported and the role of each header is normatively defined.
Proposed / staged updates
1.
feat: add EdDSA (Ed25519) as an optional algorithmUCP's JWK schema is split into EC (existing) and OKP (new) branches via
oneOf. EdDSA is OPTIONAL for general UCP verifiers; ES256 remains the universal MUST baseline. EC keys gain a tightalg/crvcoupling (ES256 with P-256, ES384 with P-384). No spec language about WBA yet — this commit just makes Ed25519 a recognized UCP algorithm.2.
feat: add WBA-compatible signature shape (single-sig dual-audience)New WBA Interop subsection in signatures.md documents the opt-in:
Signature-Agentheader (RFC 8941 Dictionary, member key matches theSignature-Inputsignature label).signature-agent;key="<label>"as a component (RFC 9421 §2.1.2 Dictionary-member component selection).ucp-agent,idempotency-key,content-digest,content-type) stay in the signed list.3.
feat: add top-level keys[] and WBA-interop deployment patternsProfile schema gains a top-level
keys[]field (RFC 7517 JWK Set) that mirrors the canonicalsigning_keys[]. When both arrays are present they MUST list the samekidset with semantically equivalent JWKs (identical RFC 7638 thumbprints).tagparameter; explicit skip semantics; SHOULD-levelkeyid↔JWK-thumbprint check; transport-identity rule scoped against payload-layer assertions.On the wire
Default UCP signature (today, unchanged)
ES256 signature against a key in
signing_keys[]. UCP verifier readsUCP-Agent, fetches profile, verifies. No changes.WBA-interop opt-in signature (new, opt-in)
One signature on the wire. UCP-shape verifiers route via
UCP-Agentand find their components (ucp-agent,idempotency-key). WBA-shape verifiers route viatag="web-bot-auth"→Signature-Agent, find theirs (@authority,signature-agent,tag,created/expires). Both verify the same bytes against the same key. Both headers can point at the same well-known URL, but implementer is also free to point to separate WBA-compatible directory.UCP profile as JWKS
The
/.well-known/ucpdocument publishes both arrays as semantic mirrors:{ "ucp": { ... }, "signing_keys": [ { "kid": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs", "kty": "OKP", "crv": "Ed25519", "x": "..." }, { "kid": "merchant-2026", "kty": "EC", "crv": "P-256", "x": "...", "y": "..." } ], "keys": [ { "kid": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs", "kty": "OKP", "crv": "Ed25519", "x": "..." }, { "kid": "merchant-2026", "kty": "EC", "crv": "P-256", "x": "...", "y": "..." } ] }RFC 7517 §5 permits additional members alongside
keysin a JWK Set, so the document is simultaneously a valid UCP profile and a valid JWK Set. UCP-classic verifiers readsigning_keys[]; WBA-shape verifiers (reading viaSignature-Agent) readkeys[]. I'm proposing this shape as an interim step towards replacing/deprecatingsigning_keys[]in favor ofkeys[]in separate PR, which can target next UCP version.Backwards compatibility
signing_keys[]remain valid.keys[]is OPTIONAL.UCP-Agent(noSignature-Agent).Where this gets us vs desired state
After this PR lands, a UCP+AP2+WBA-interop merchant operates two keys in the same
signing_keys[]array (and mirrors them inkeys[]if publishing JWKS-superset form):merchant_authorizationJWT, per AP2 v0.2 §Payment Mandate.Two additional moves collapse this to one key, one artifact:
idfield structurally satisfies. Once accepted upstream, a UCP+AP2 merchant can use a single Ed25519 key for both layers.keys[]to canonical and deprecatessigning_keys[]— separate follow-up PR (not in scope here). Profiles publish a singlekeys[]array; the document is a valid JWK Set without dual-publication.With both in place: one Ed25519 key, one
keys[]array, one profile document that's also a valid WBA directory. No mirroring, no dual-keying, no separate signing-key field. The wire format and verifier algorithm in this PR don't change in that future — they're already pointed at it.Checklist