Read the webhook signature from the X-Webhook-Signature header Fizzy actually sends
What
Fizzy sends the HMAC-SHA256 delivery signature in X-Webhook-Signature — app/models/webhook/delivery.rb builds the delivery headers as "X-Webhook-Signature" => signature, the webhook settings page says the same, and docs/api/sections/webhooks.md refers to it by that name. The SDK told consumers to read X-Fizzy-Signature instead.
- TypeScript —
WebhookReceiverdefaultedsignatureHeadertox-fizzy-signature. Nowx-webhook-signature. - Swift / Kotlin — the
WebhookVerifier/verifyWebhookSignaturedoc-strings and examples pointed atX-Fizzy-Signature. Corrected. - SECURITY.md — documented
X-Fizzy-Signature. Corrected.
Failure mode on the old TypeScript default
Fail-closed, not fail-open. handleRequest only consults the header when a secret is configured; it looked up x-fizzy-signature, found nothing on a real Fizzy delivery, and threw WebhookVerificationError — so every receiver configured with a secret rejected every genuine delivery as unsigned. Nothing was ever accepted unverified. A receiver without a secret skips verification regardless of header, unchanged.
Tests
New WebhookReceiver signature header block in typescript/tests/fizzy.test.ts:
- a delivery signed under
x-webhook-signatureis accepted by default (fails on the old default); - a delivery with no signature header is rejected with
WebhookVerificationError; - a delivery signed under
x-fizzy-signaturealone is rejected (pins the header name from the other side); signatureHeaderoverride still honored; no-secret path still skips verification.
Not changed
- Go and Ruby verification takes the signature string as an argument and carries no header name in code or docs — nothing to fix there.
- Rust (open
rust-sdkbranch) already usesX-Webhook-Signature; untouched. - Spec / conformance — neither
spec/fizzy.smithynor the conformance fixtures carry the signature header name (the Smithy model covers theWebhookresource and delivery request shape, and the conformance suite exercises the client side only), so there is no single constant the languages could derive from today. Each language hand-writes the name; this PR aligns them rather than adding pipeline machinery for one string.
Gates
npm test (97 passing), npm run lint (only the pre-existing gating.ts unused-import warning), npm run typecheck clean. Swift and Kotlin changes are doc comments only.
Summary by cubic
Reads webhook signatures from the X-Webhook-Signature header Fizzy actually sends, instead of the wrong X-Fizzy-Signature name.
- The TypeScript receiver defaulted to
x-fizzy-signature, so any receiver with a secret rejected every real delivery as unsigned (fail-closed). Now defaults tox-webhook-signature. - Corrects the header name in Swift and Kotlin doc-strings and in
SECURITY.md. signatureHeaderoverride and the no-secret skip path are unchanged; Go, Ruby, and Rust already use the right header.