Skip to main content
Version: Current

verifyWebhook

@rotorsoft/act-root


@rotorsoft/act-root / act-http/src/receiver / verifyWebhook

Function: verifyWebhook()

verifyWebhook(headers, body, secret, options?): VerifyResult

Defined in: libs/act-http/src/receiver/verify.ts:65

Verify an inbound webhook's signature and timestamp against the shared secret. Pair with the sender side: configure webhook({ secret }) from @rotorsoft/act-http/webhook.

Returns { ok: true } on success or { ok: false; reason } on failure. The reasons are:

  • missing-signature — no X-Webhook-Signature header, value was an array, or value was empty.
  • missing-timestamp — no X-Webhook-Timestamp header, value was empty, or value isn't a parseable integer.
  • stale — timestamp older than maxAgeSeconds from now.
  • future — timestamp more than maxAgeSeconds ahead of now.
  • bad-signature — signature header didn't start with sha256=, wasn't 64 hex chars, or the recomputed HMAC didn't match (constant-time compare).

The signed payload is ${timestamp}.${body}, so body must be the raw request body bytes. Any pre-parse normalization (whitespace trimming, JSON re-stringification) would change the hash and reject every otherwise-valid request. The receiver subpaths' adapters pass the raw body alongside the parsed one.

Uses Node's crypto.timingSafeEqual for the final comparison to avoid signature-equality timing attacks.

Parameters​

headers​

Record<string, string | string[] | undefined>

body​

string

secret​

string

options?​

VerifyOptions

Returns​

VerifyResult