Skip to content

Add verifyRequestSignature helper for webhook validation#227

Merged
mike-engel merged 1 commit into
customerio:mainfrom
brian717:feature/verify-webhook-signature
Jul 2, 2026
Merged

Add verifyRequestSignature helper for webhook validation#227
mike-engel merged 1 commit into
customerio:mainfrom
brian717:feature/verify-webhook-signature

Conversation

@brian717

@brian717 brian717 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a verifyRequestSignature helper so consumers can verify that incoming Customer.io reporting webhooks are authentic, addressing #155.

Also, updated the README under a new "Webhooks" section. If this is not important enough to take up space in the main README, it can be removed (or maybe moved elsewhere?)

Testing

11 new unit tests in test/webhooks.ts, lint and prettier run. All passed locally.

Notes

  • Encoding is hex, matching Customer.io's Go example and the Node .digest('hex') convention (the docs don't state it explicitly).
  • This is added in a separate libs/webhooks.ts file, rather than in utils like the previous PR (feat: create util function for verifying webhook signature #159). Either way makes sense to me, I can move it to utils if requested.

Note

Medium Risk
Touches webhook authentication logic; incorrect verification could accept forged webhooks, though the change is additive and well-tested.

Overview
Adds verifyRequestSignature so apps can confirm Customer.io reporting webhooks are authentic (addresses #155). The helper recomputes HMAC-SHA256 over v0:<timestamp>:<body> with the webhook signing secret, compares the hex digest to X-CIO-Signature via timingSafeEqual (with length checks first), and returns false for bad/missing signatures while throwing MissingParamError if signingSecret is empty. It accepts raw string or Buffer bodies and string or number timestamps.

Implementation lives in new lib/webhooks.ts, re-exported from the package entrypoint. The README gains a Webhooks section with an Express-style example and option docs. test/webhooks.ts adds 11 unit tests covering valid signatures, a golden hash, tampering, wrong secret/timestamp, malformed signatures, and empty secret.

Reviewed by Cursor Bugbot for commit 496c2fd. Bugbot is set up for automated code reviews on this repo. Configure here.

Adds a helper to verify that incoming reporting-webhook requests genuinely
came from Customer.io, addressing customerio#155.

Customer.io signs each request with an HMAC-SHA256 over `v0:<timestamp>:<body>`
keyed with your webhook signing secret, sent hex-encoded in the X-CIO-Signature
header. The helper recomputes that signature and compares it in constant time
(crypto.timingSafeEqual), guarding the length first. It accepts string or Buffer
bodies to avoid lossy re-serialization, returns false for a missing/malformed
signature, and throws MissingParamError only for an empty signing secret.

Includes 11 unit tests (100% coverage), a README section, and the package export.
@mike-engel mike-engel merged commit b0288a4 into customerio:main Jul 2, 2026
7 checks passed
@mike-engel

Copy link
Copy Markdown
Collaborator

Thanks for this @brian717! This will go out in the next release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants