Webhook Engineering · Chapter 2 · 12 min
Sign payloads with HMAC
Compute HMAC-SHA256 signatures with WebCrypto and understand exactly what is being signed.
What HMAC gives you
HMAC-SHA256 combines a shared secret with the message bytes to produce a unique 32-byte tag. Without the secret, nobody can compute a valid tag for a modified payload, ensuring integrity. It proves integrity and authenticity, not confidentiality, so the body remains readable on the network path. This mechanism is the industry standard for securing communications between independent services like ub3r and your app.
Sign the bytes, not the object
Sign the exact raw request body as it was sent over the wire to avoid issues. If the receiver re-serialises it before verifying, the signature will likely fail due to formatting changes. Frameworks that eagerly parse bodies into objects are the number one cause of signature mismatch errors. Always access the raw buffer to ensure you are looking at the same bytes the ub3r platform signed.
Waiting for output…
A header format that ages well
A good signature header includes both a timestamp and a versioned signature tag for clarity. The format t=timestamp,v1=signature is widely used because it's easy to parse and extend over time. Include the timestamp inside the signed string so an attacker cannot replay an old body with a fresh timestamp. This prevents replay attacks where a valid but old message is sent again to trigger action.
Mx-Signature: t=1760536800,v1=5f1c0b8e9...Rotating secrets safely
Version the scheme so you can rotate algorithms or secrets without causing downtime for your users. During a rotation, you can include multiple signature values in the header for the consumer to check. The consumer should iterate through all signatures and succeed if any of them match the secret. This allows for a smooth transition where both old and new secrets are valid for a short time.
Debugging Signature Failures
If signatures are failing, the most likely culprit is the way your server reads the request body. Check for any middleware that might be modifying the body before it reaches your verification logic. Logging the raw bytes on both ends can help identify discrepancies in character encoding or whitespace. Once the raw bytes match, the HMAC calculation should produce identical results every time.
Discussion (3)
The distinction between 'sent' and 'delivered' finally clicked for me here. We had dashboards treating them as the same thing for a year.
Good point — we're adding a short section on this in the next revision.
Would love a follow-up on how this behaves under carrier throttling. We see very different numbers per route.