How to use the Webhook Signature Verifier & Debugger
Verify, generate, and debug HMAC webhook signatures for Stripe, GitHub, Slack, Shopify, Twilio, SendGrid, and any custom provider — entirely in your browser. Inspect the canonical signing string, replay window, raw-body diagnostics, and produce a backend verifier snippet with timing-safe comparison. Useful for debugging "invalid signature" errors, building integration tests, and validating new webhook handlers. Signing secrets never leave your machine.
What it does
- Verifies HMAC-SHA256 / SHA1 webhook signatures for Stripe (
Stripe-Signature, v1), GitHub (X-Hub-Signature-256), Slack (v0:), Shopify (X-Shopify-Hmac-Sha256), Twilio (URL-based), SendGrid (Ed25519), and custom HMAC schemes.
- Auto-detects the provider from the signature header.
- Shows the canonical signing string for each provider (
timestamp.body, v0:timestamp:body, raw body, full URL, etc.).
- Generates a signature so you can build test fixtures.
- Diagnoses common mismatches: raw-body changes, wrong secret/env, timestamp out of tolerance, encoding mismatches, URL drift behind proxies.
- Produces a backend verifier snippet with timing-safe comparison in Node / Python / Go / Java / Ruby.
When to use it
- A webhook hits your app but fails signature verification — you need to find out why.
- You need to confirm the exact canonical payload a provider signs.
- Testing custom HMAC webhook logic locally without scripting a verifier.
- You want a copy-ready backend verifier with timing-safe comparison.
- Generating fixtures for integration tests of a webhook endpoint.
- Onboarding to a new provider's webhook scheme.
How to use it
- Pick the provider (Stripe, GitHub, Slack, Shopify, Twilio, SendGrid, or Custom) — or paste the signature header and click Auto-detect provider.
- Paste the raw payload (exact bytes, not a re-serialized JSON), the signature header, and the signing secret.
- Click Verify — the tool shows match / mismatch, the canonical string, and diagnostics.
- For test fixtures, switch to Generate Signature with your own payload and secret.
- Open Code Snippets for a ready-to-paste backend verifier in your language.
- Use Reports to share a sanitized diagnostic that excludes the secret.
Why signatures fail
- Raw body changed. Most providers sign the exact bytes — JSON pretty-printing or framework reserialization breaks verification.
- Wrong secret or environment. Stripe Dashboard endpoint secrets differ from Stripe CLI; test mode and live mode use different secrets.
- Timestamp out of tolerance. Stripe and Slack reject signatures older than ~5 minutes by default — guards against replay.
- Encoding mismatch. Shopify uses Base64; Stripe, GitHub, Slack use hex. The header format must match.
- Twilio URL drift. Reverse proxies or load balancers can change scheme or host, breaking Twilio's URL-based signature.
- Multiple signatures in one header. Stripe's
v1= can include several values (key rotation) — verify against any.
FAQ
- How do I verify a Stripe webhook signature? Select Stripe, paste the raw body, the
Stripe-Signature header, and the endpoint secret. The tool shows the canonical string and signature comparison.
- Why does my webhook signature not match? Almost always: raw-body mutation, wrong secret, or timestamp out of tolerance. The diagnostics tab points at the cause.
- What is the canonical signing string? The exact byte sequence the provider runs HMAC over — varies by provider (
timestamp.body, v0:timestamp:body, the full URL + body, etc.).
- Is my signing secret uploaded? No. Verification runs in your browser using Web Crypto, and secrets are never included in share links or reports by default.
- How do I generate a test webhook signature? Use the Generate Signature tab — paste your payload and secret to produce the header the verifier expects.
- Can I add a custom provider? Yes — pick Custom and configure the canonical-string template, hash algorithm, and encoding.
Runs locally in your browser using Web Crypto. No uploads. Signing secrets are never included in share links or reports by default.