feat(signing): add createWebhookVerifier factory for secure-by-default webhook verification#928
Merged
Conversation
…t webhook verification Mirrors createExpressVerifier: stores are instantiated once at creation time and captured in closure scope so replay dedup works across all requests on the same verifier instance. Fixes the request-signing / webhook-signing ergonomics parity gap raised in #926. Closes #926 Session: https://claude.ai/code/session_01UWbckodGXcJVoH1Z1VpLjv
… multi-replica JSDoc - test/webhook-verifier-factory.test.js: remove unused `verifyWebhookSignature` import (github-code-quality bot) - middleware.ts: tighten replayStore/revocationStore JSDoc to MUST language, matching the wording used on createWebhookVerifier so both factories carry the same multi-replica warning Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Closes #926
Summary
createWebhookVerifier(options)factory tosrc/lib/signing/webhook-verifier.ts— mirrorscreateExpressVerifierfor the webhook profilecreateWebhookVerifierandCreateWebhookVerifierOptionsfrom@adcp/client/signing/server(and the aggregate@adcp/client/signingbarrel)verifyWebhookSignatureis unchanged — requiredreplayStore/revocationStorestay required on the low-level functionminor— new additive exports, no breaking changes)Why a factory and not optional params on
verifyWebhookSignatureThe initial proposal in #926 suggested making
replayStore/revocationStoreoptional directly onverifyWebhookSignature. Pre-triage expert review (security + code) flagged that as a blocker: defaulting stores inside a per-request function would silently defeat replay protection for any caller who constructs a new options object per request (the natural pattern for a stateless function). ThecreateExpressVerifierprecedent is structurally correct because it's a factory — stores live in closure scope. This PR follows the same pattern.What was tested
npm run format:check— passesnode --test test/webhook-verifier-factory.test.js— 3/3 passnode --test test/lib/webhook-signing-vectors.test.js test/webhook-verifier-error-codes.test.js— 34/34 pass (no regressions)npm run build:lib— emits correctly; pre-existingtsconfig.lib.jsonTypeScript config warnings are repo-wide and unrelated to this changePre-PR review
Omit<>constraint prevents stale-store overwrite via spread; multi-replica MUST language strengthened per feedbackNits noted (not fixed — out of scope)
createExpressVerifierinmiddleware.tscould similarly strengthen its multi-replica JSDoc (separate PR)Session: https://claude.ai/code/session_01UWbckodGXcJVoH1Z1VpLjv
Generated by Claude Code