HMAC, defined in RFC 2104, is H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ message)): the key is padded with zeros to the hash’s block size — 64 bytes for MD5, SHA-1 and SHA-256, 128 for SHA-384 and SHA-512 — XORed with two constants, and the hash is applied twice. A key longer than the block is hashed first, which is the step home-made implementations forget, so they fail only on long secrets. The result is as long as the hash: 32 bytes for HMAC-SHA-256. Everything here is computed in plain arithmetic in the page, checked against the RFC 4231 and RFC 2202 test vectors and, for SHA-384 and SHA-512, the FIPS 180-4 examples.
Because HMAC works on bytes, a mismatch almost always means the two sides disagree about bytes, and the result panel says which bytes were used. The key: a secret shown as 64 hex characters is 64 bytes if used as text but 32 if decoded as hex, and the two give unrelated MACs. GitHub, Stripe and Slack all use their secret as text — Stripe’s whsec_ prefix included — whereas services following Standard Webhooks, Svix among them, base64-decode the part after whsec_. The message: a trailing newline or a CRLF is signed like any other byte, and a browser text area turns CRLF into LF, so paste hex or base64 when exact line endings matter. The output: hex and base64 of one MAC look nothing alike, so the checker reads either, and strips a sha256= or v0= prefix. It compares in constant time, because === stops at the first differing character and so tells an attacker how much of a guess was right.
The presets follow each provider’s current documentation. Stripe signs the timestamp, a full stop and the raw body, and sends Stripe-Signature: t=…,v1=… in hex; v0 is a fake signature on test events that Stripe says to ignore, and while a secret is being rolled the header carries one v1 per active secret. GitHub signs the raw body and sends X-Hub-Signature-256: sha256=…, alongside the older SHA-1 X-Hub-Signature. Slack signs v0:, the X-Slack-Request-Timestamp, a colon and the body, and sends X-Slack-Signature: v0=…. The GitHub and Slack presets reproduce the examples in their documentation exactly. Stripe’s libraries and Slack’s own example also reject a timestamp more than five minutes from the receiver’s clock, to stop replays; this page checks the signature only, not its age.