Webhook Signature Verifier avatar

Webhook Signature Verifier

Pricing

Pay per usage

Go to Apify Store
Webhook Signature Verifier

Webhook Signature Verifier

Verify HMAC-SHA256/SHA1/SHA512, Stripe-Signature, GitHub X-Hub-Signature-256, Apify webhook, and Bearer-token webhook payloads against a shared secret. Constant-time compare, per-check pass/fail, structured reason codes for n8n/Make/Sheets alerts.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Nikita S

Nikita S

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Verify HMAC-SHA256 / SHA1 / SHA512, Stripe-Signature (t=...,v1=...), GitHub X-Hub-Signature-256, Apify webhook resource HMAC, and Bearer-token webhook payloads against a shared secret. Constant-time compare, per-check pass/fail with structured reason codes — built for n8n → Slack style alerts and Apify-as-a-step workflows.

Why a separate Actor?

There is no Store Actor that handles more than one signing scheme. devnomad/webhook-validator and stalniad/webhook-validator are HTTPS endpoints, not Apify Actors. Most teams have to write a per-provider n8n Function node or Make Module. This Actor unifies the common signing schemes behind one input shape, with one output row per check.

Quick start

{
"mode": "hmac_sha256",
"secret": "whsec_...",
"signature": "sha256=abc...",
"payloadText": "{\"event\":\"push\",\"id\":\"evt_1\"}"
}

Output: one row per source/payload with ok: true|false|null, reason, mode, matched, and recomputed (the expected signature, hex-encoded) for debugging.

Inputs

FieldTypeNotes
modestringhmac_sha256 (default) / hmac_sha1 / hmac_sha512 / stripe / apify_webhook / bearer
secretstringShared signing secret (Stripe whsec_..., GitHub webhook secret, etc.)
signaturestringRaw header value (sha256=..., t=...,v1=..., or Bearer ...)
tokenstringExpected Bearer token (when mode=bearer)
timestampstringOptional override for Stripe t= (skips skew check)
toleranceSecondsintStripe mode clock-skew tolerance (default 300)
payloadTextstringRaw webhook body to verify (one check per top-level config)
contentTypestringMIME of payloadText (default application/json)
payloadUrlsstring[]Public URLs whose response body is verified (one check per URL)
rawBodystringExtra inline body for an extra check (no fetch)
checksobject[]Array of {mode, secret, signature, token, rawBody} for batch verification

Output

Each row:

{
"source": "https://example.com/hook",
"format": "json",
"mode": "hmac_sha256",
"ok": true,
"reason": "matched",
"recomputed": "f0e1...",
"matched": true,
"check": { "mode": "hmac_sha256", "headerName": null, "hasTimestamp": false, "toleranceSeconds": 300 }
}

A SUMMARY record is also written with totalChecks, passed, failed, errors, and per-mode counts.

Supported modes

  • hmac_sha256 / hmac_sha1 / hmac_sha512 — accepts both hex and base64 encodings; the sha256= / sha1= / sha512= prefix is stripped automatically. Constant-time compare via crypto.timingSafeEqual.
  • stripe — parses t=...,v1=... header, recomputes HMAC-SHA256 over ${t}.${rawBody}, optional timestamp skew check.
  • apify_webhook — Apify webhooks sign only the resource object (stringified). The Actor extracts it from a parsed JSON body and verifies the HMAC.
  • bearer — constant-time compare of provided Bearer ... token against expected.

Pairs with

  • ../webhook-payload-debugger — inspect the payload after signature verifies.
  • ../jws-verifier — verify JWT/JWS-style tokens (Auth0/Clerk/Cognito).
  • ../security-headers-validator — quick webops audit on a public URL.

Pricing / cost expectations

Default 256 MB / 512 MB. Pure Node crypto + fetch; per check is sub-millisecond of CPU. Pay-per-event scheduled to activate after public launch: 1 charge per signature_check event (one webhook = one charge).

FAQ

Does it support JWT / JWS? No — see the ../jws-verifier Actor for that. This Actor targets raw HMAC, Stripe, GitHub, Apify, and Bearer.

Does it fetch URLs? Yes, via payloadUrls[]. Public URLs only, no auth, no proxy.

Is the compare timing-safe? Yes — uses crypto.timingSafeEqual on the recomputed and provided signatures.

Does it log secrets? No — secret/token are read once into memory and never echoed in SUMMARY or dataset rows.

License

MIT.