Spent two days chasing intermittent HMAC verification failures on inbound payment webhooks. Staging passed every time. Production failed roughly 1 in 40 requests, no pattern in payload size or endpoint.
Traced it to Express's body-parser. It parses the raw request into a JS object before our verification middleware runs. We were re-serializing that object with JSON.stringify to compute the HMAC, assuming it would match what the provider signed. It doesn't, reliably.
JSON.stringify doesn't guarantee the same key order, whitespace, or number formatting as whatever serializer the provider used server-side. Most of the time the object happens to stringify back to identical bytes. Sometimes a field with a trailing zero, a differently ordered object, or unicode escaping changes just enough to flip the signature.
The fix was mundane: capture the raw body as a Buffer before any parsing touches it, verify against those exact bytes, then parse for business logic. Two lines of middleware ordering, and the failure rate went to zero over three weeks of traffic.
The provider's docs did say "verify against the raw request body." I read that as a suggestion, not a byte-for-byte requirement.
Anyone else lose time to a framework silently reserializing something before a signature check?
Top comments (0)