Spoold Logo

Webhook HMAC Verifier

Guide

Which webhook?

The check stays in the browser. Use a test secret — it is not saved with history.

Guide: Webhook HMAC Verifier

↑ Back to tool

What is this tool?

This webhook HMAC verifier checks whether a webhook signature is valid for a given secret and request body. It supports the three most common schemes: Stripe (Stripe-Signature), GitHub (X-Hub-Signature-256), and Slack (X-Slack-Signature). It computes HMAC-SHA256 with the browser's Web Crypto API, shows the expected digest, and tells you whether it matches.

Use it to debug the classic "signature verification failed" error: paste the secret, the raw body, and the header, and see immediately whether the problem is the secret, the payload bytes, or the timestamp.

Security warning

⚠️ Do not paste production secrets on untrusted machines

Anyone with a webhook secret can forge events your server will trust. This tool never uploads or stores the secret (history and shares exclude it), but browser extensions, screen sharing, shell history, shared computers, and clipboard managers can still leak it. Use test-mode or temporary secrets when debugging, and rotate any secret you suspect was exposed.

Why use a webhook signature verifier?

  • Find out in seconds whether a webhook signature mismatch is a secret problem or a body problem
  • Generate the expected signature to compare with your server logs
  • Learn each provider's signed-payload format without reading three sets of docs
  • Test local handlers and replay captured payloads from the Stripe CLI, ngrok, or provider dashboards

Key features

  • Provider chips — Stripe, GitHub, Slack with the right header and fields for each.
  • Live match / mismatch chip — Verification runs on every change, locally.
  • Expected signature — View and copy the computed hex digest.
  • Replay warning — Flags matching signatures with timestamps outside a 5-minute tolerance.
  • Example loader — Fills a self-consistent test payload.
  • History without secrets — Re-open past checks; re-enter the secret to verify again.

How to use

  1. Pick a provider — Stripe, GitHub, or Slack.
  2. Enter the secret — Endpoint secret, webhook secret, or signing secret.
  3. Paste the raw body — Exactly as received, without re-formatting.
  4. Paste the header — And for Slack, the request timestamp.
  5. Read the result — Match, mismatch, or what is missing. Copy the expected digest if needed.

Provider schemes

ProviderHeaderSigned payload
Stripet=…,v1=…${t}.${body}
GitHubsha256=…The raw body
Slackv0=… + timestamp headerv0:${timestamp}:${body}

Best practices

  • Verify on the raw body — Capture bytes before any JSON middleware parses them.
  • Use constant-time comparison in production, and enforce a timestamp tolerance to block replays.
  • Keep secrets in env vars or a secret manager, never in source control or chat.
  • Rotate secrets after a leak or when a teammate leaves.

Common mistakes

  • Re-serialized JSON — JSON.stringify(req.body) rarely equals the original bytes.
  • Wrong secret — Slack bot tokens and API keys are not signing secrets; Stripe endpoints each have their own secret.
  • Trailing newline — Copying a body from a terminal can add or strip a final newline.
  • Legacy sha1 — Use X-Hub-Signature-256, not X-Hub-Signature.

FAQ

Is it safe to paste my webhook secret here?

Verification runs entirely in your browser with Web Crypto, and the secret is never sent to a server, saved to history, or included in shares. Even so, prefer test-mode or rotated secrets, and never paste production secrets on a shared or untrusted machine.

Why does my signature not match?

The usual cause is a modified body. HMAC covers the exact raw bytes, so pretty-printed JSON, trimmed whitespace, or a body re-serialized by your framework will fail. Also confirm the secret belongs to the same endpoint and environment (live vs test).

Which Stripe secret do I use?

The endpoint signing secret that starts with whsec_, from the Stripe Dashboard webhook endpoint (or the Stripe CLI listen output). It is used as-is, including the whsec_ prefix.

Does this check the timestamp too?

For Stripe and Slack the timestamp is part of the signed payload. A matching signature with a timestamp older than five minutes is flagged with a replay warning, though your server should enforce that tolerance itself.

Is the comparison constant-time?

Yes, hex digests are compared with a constant-time loop. In production code use your SDK's verify helper or timingSafeEqual rather than ===.

Core: webhook signature verification, hmac sha256 webhook, verify webhook signature online, webhook secret tester, webhook signature mismatch.

Providers: stripe-signature header, stripe webhook signing secret, x-hub-signature-256, github webhook secret, slack signing secret v0, x-slack-request-timestamp, replay attack timestamp tolerance.

Similar tools

You might also find these developer tools useful:

Conclusion

This webhook HMAC verifier makes signature debugging fast and private. For hashing and HMAC experiments, try the Hash Generator; to replay a request, use the HTTP Request tool.