Webhook HMAC Sign / Verify
Compute HMAC signatures for webhook bodies (Stripe, GitHub…).
Overview
The webhook HMAC sign and verify tool computes the message-authentication signatures that webhook senders (Stripe, GitHub, Slack, Shopify, and many others) attach to their payloads. Pick the hash algorithm, paste the shared secret and the raw request body, and the tool returns the HMAC in hex or base64. The verify mode does the opposite — confirms a signature header matches a body.
Developers integrating webhooks who need to verify the request actually came from the documented sender, support engineers reproducing a customer's failed verification, and security teams auditing inbound webhook handling all need an HMAC signer/verifier. Long-tail keywords covered: verify Stripe webhook signature, compute GitHub webhook HMAC-SHA256, and check webhook payload integrity.
How it works
HMAC (RFC 2104) combines a cryptographic hash function with a shared secret to produce a fixed-length tag that anyone with the secret can verify. Webhook senders compute HMAC(secret, body) on the raw request body and attach the result as a header like X-Hub-Signature-256: sha256=... (GitHub) or Stripe-Signature: t=...,v1=... (Stripe). The receiver recomputes the HMAC with their copy of the secret and compares constant-time.
Two details bite people. The "body" must be the exact byte sequence the sender hashed — re-serialising parsed JSON drops whitespace and breaks the signature. And the comparison must use a constant-time function (crypto.timingSafeEqual in Node, hmac.compare_digest in Python) to prevent timing attacks.
Examples
- GitHub:
HMAC-SHA256(secret, body)returns9a4c..., attached asX-Hub-Signature-256: sha256=9a4c.... - Stripe: signs
timestamp.bodywithHMAC-SHA256(secret, t + "." + body), header carriest=andv1=parts. - Slack: signs
v0:t:bodywithHMAC-SHA256(slack_signing_secret, ...), header isX-Slack-Signature: v0=.... - Shopify: signs the raw body with
HMAC-SHA256(secret, body)and base64-encodes the result.
FAQ
Why does parsing the JSON break my signature check?
Most parsers re-serialise to a canonical form (sorted keys, trimmed whitespace) that does not match the original bytes. Always compute the HMAC over the raw request body, before any parsing.
Should I use HMAC-SHA1 or HMAC-SHA256?
SHA-256. SHA-1 is deprecated by NIST; webhook providers that still send SHA-1 signatures usually emit a SHA-256 alternative alongside that should be preferred.
Is comparing strings with == safe?
No. Use a constant-time comparison helper to avoid leaking timing information about which byte mismatched.
What if my secret leaks?
Rotate it immediately at the sender's dashboard, update your handler, and treat any payload received during the window as untrusted. Some providers let you run two secrets in parallel during the rotation window.