Verify a webhook signature
Compute the HMAC-SHA-256 signature for a payload and secret in the formats providers publish, and compare it with the header you were sent. The secret never leaves your browser.
What it checks
- The exact string that gets signed, which for Stripe is the timestamp, a dot and the body, and for Slack is v0, the timestamp and the body joined by colons.
- The computed signature in the scheme format: bare hex, bare base64, GitHub sha256=, Stripe t= and v1=, Slack v0=, Shopify base64.
- Whether the supplied signature matches, compared without an early return on the first differing byte.
- On a mismatch, what the supplied signature was actually computed over, tested against the bodies people sign by accident: the re-serialised JSON a body parser produces, a trailing newline added or removed, and CRLF line endings.
- Whether a length difference points at a different hash function rather than a different secret, since SHA-1 gives 40 hex characters and SHA-256 gives 64.
- The age of the timestamp against the replay window Stripe and Slack document, which is 300 seconds for both.
What is not stored
Nothing is stored and nothing is sent. This checker is JavaScript that runs inside your browser tab, so the value you paste never reaches h2check.org or any other server. Close the tab and it is gone.
Limits
- The signature covers the raw request body, byte for byte. A body pasted out of a pretty-printing log viewer is no longer those bytes and will not reproduce the signature.
- Only HMAC-SHA-256 is implemented. A provider that signs with SHA-1, with an asymmetric key, or inside a JWS envelope is not covered, and GitHub X-Hub-Signature without the -256 suffix is SHA-1.
- A matching signature proves the body and the secret, not that the request is fresh. Without a timestamp check a captured request replays unchanged.
- A browser tab is a safe place for a sandbox secret and the wrong place for a production one. A production secret pasted into any web page, including this one, has to be rotated.
Procedures that explain the result
- Github webhook signature verification
- How to check webhook signature
- Stripe webhook signature verification
- Webhook replay attack
- Webhook signature verification failed
Put it on your own page
Link to it with the value filled in, and the checker runs as soon as the page opens.
<a href="https://h2check.org/tools/webhook-signature/">Verify a webhook signature</a>