Skip to main content
Reader signs every webhook delivery with HMAC-SHA256 when you provide a secret. Verify the signature before trusting the payload. Without verification, anyone who guesses your endpoint URL can forge events.

The signing scheme

Reader computes:
And sends both the signature and the timestamp as headers:
Your job: reconstruct the same HMAC with the same inputs and check they match in constant time.

Node.js / Express

Use express.raw() for the webhook route. You must have the unparsed bytes to hash.

Python / FastAPI

Next.js (App Router)

Common pitfalls

  • Parsing the JSON before hashing. If you JSON.parse then re-stringify, the bytes won’t match what Reader signed. Always use the raw body.
  • Missing express.raw(). Express’s default JSON middleware parses the body and loses the original bytes. The webhook route needs a separate middleware.
  • String comparison instead of constant-time compare. A === comparison leaks timing information. Use crypto.timingSafeEqual (Node) or hmac.compare_digest (Python).
  • No replay check. A captured webhook can be replayed by an attacker unless you reject stale timestamps.

Next