Skip to content

Storyboard / SDK skill on-ramp inventory: HMAC vs RFC 9421 #4270

@EvgenyAndroid

Description

@EvgenyAndroid

Companion to #4205 — taking the storyboard / SDK skill on-ramp pass I self-pledged ("inventory which currently reference HMAC vs RFC 9421 and file a follow-up issue").

Framing

Per @bokelley's reframe in #4205: the right metric isn't "% migrated" against the installed base (which is ~empty). It's "no new HMAC implementers after date X," enforced via four on-ramp surfaces:

This issue covers surface 4. Where SDK-bundled skills + storyboard-adjacent compliance / schema docs frame webhook auth, do they steer new buyers toward 9421 or do they leave HMAC as the path of least resistance?

Inventory (against adcp-3.0.8)

✅ Already well-framed (no action)

Surface Treatment
compliance/universal/webhook-emission.yaml Calls HMAC "deprecated fallback"; grades 9421 as default; legacy buyers graded only on idempotency phases.
compliance/universal/signed-requests.yaml RFC 9421 only; no HMAC mention.
compliance/test-vectors/webhook-signing/README.md RFC 9421 throughout; production keys MUST be minted under own jwks_uri.
schemas/3.0.8/core/push-notification-config.json "By default, webhooks are signed with the AdCP RFC 9421 profile"; auth block is the deprecated fallback, removed in 4.0. Best-in-class framing.

🟡 Stale framing — actively recommends HMAC

schemas/3.0.8/core/reporting-webhook.json

Line 24 description on the authentication block:

Supported: ['Bearer'] for simple token auth, ['HMAC-SHA256'] for signature verification (recommended for production)

This contradicts push-notification-config.json's framing (HMAC is the deprecated fallback there). Two adjacent webhook config schemas tell new buyers different things. Worse, on this schema authentication is required (line 63) — there is no path to opt into 9421 for reporting webhooks at all.

Suggested fix: align with push-notification-config.json's description; make authentication optional and document that omitting it selects the default 9421 profile (or document why reporting webhooks are different and intentionally locked to legacy).

schemas/3.0.8/enums/auth-scheme.json

Enum is [\"Bearer\", \"HMAC-SHA256\"] with a description that doesn't mention deprecation. A buyer reading this enum in isolation has no signal these are legacy options. Suggested fix: extend the description to note these are legacy auth-block options for buyers who haven't adopted the default 9421 webhook profile.

🔴 Silent — agent on-ramp skills don't mention webhook auth at all

The skills/*/SKILL.md files are what SDKs ship to teach LLM agents the wire contract. They cover idempotency_key, the oneOf account discriminator, async status:'submitted' polling, error recovery from adcp_error.issues[] — but none of them mention webhook signing:

  • skills/call-adcp-agent/SKILL.md (cross-cutting buyer-side basics) — zero webhook auth references
  • skills/adcp-signals/SKILL.md — only "Poll or use webhooks to check completion status" (line 178); no auth guidance
  • skills/adcp-media-buy/SKILL.md — only "Poll or use webhooks to check completion status" (line 392); no auth guidance
  • skills/adcp-creative/SKILL.md — no webhook references
  • skills/adcp-governance/SKILL.md — no webhook references

A new buyer agent built from these skills will reach for push_notification_config.authentication (the visible field in the schema) before learning that omitting it selects the modern path. The on-ramp surface that matters most for "no new HMAC implementers" is silent on the choice.

Suggested fix: a short section in call-adcp-agent/SKILL.md (cross-cutting, all buyer agents load this first) titled e.g. "Webhook signing — default to RFC 9421":

  • Default behavior: omit push_notification_config.authentication → seller signs with 9421 against the JWKS published at its brand.json agents[].jwks_uri
  • Buyer verifies via the published JWKS; no shared secret crosses the wire
  • Legacy authentication block (Bearer / HMAC-SHA256) is the deprecated fallback for receivers that haven't adopted 9421; removed in AdCP 4.0
  • Link to docs/building/implementation/security.mdx#webhook-callbacks for full profile + verifier checklist

That single section closes the silent-default trap across all five protocol skills, since they all > Buyer-side basics ... live in skills/call-adcp-agent/SKILL.md.

Out of scope

  • schemas/core/assets/webhook-asset.json (DCO outbound webhook, separate auth model — webhook-security-method.json enum: hmac_sha256/api_key/none). Different surface, not part of buyer push-notification webhooks.
  • Live docs at adcontextprotocol.org/docs/building/implementation/security.mdx — those are tracked under docs: add RFC 9421 request signing guide #3064 (docs default to RFC 9421) and out of scope here. This issue scoped to bundled storyboard / SDK skill / schema descriptions only.

Suggested resolution

Two-PR shape:

  1. Schema PR — fix reporting-webhook.json description (and consider making authentication optional with 9421 default); add a deprecation hint in auth-scheme.json enum description.
  2. SDK skill PR — add a webhook-signing section to skills/call-adcp-agent/SKILL.md so all five protocol skills inherit the framing.

Happy to take a first pass on either if a maintainer wants to triage rough scope first.

References

Filed by an agent vendor consuming the bundled adcp-3.0.8 skills + schemas; happy to discuss what "agent on-ramp" reads like from the consumer side.

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.needs-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasschemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygiene

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions