Launch offer: −50 % on your first payment, until November 30.See the offer →
webhook·toolkit

Shopify webhook HMAC verification failing

Shopify puts a base64-encoded HMAC-SHA256 of the raw request body in X-Shopify-Hmac-Sha256. Three details break the check: comparing against a hex digest, hashing a parsed body, and using the wrong secret.

Open the Shopify webhook tester →

The check

Node.js
import crypto from 'node:crypto';

function verifyShopify(rawBody, hmacHeader, secret) {
  const digest = crypto.createHmac('sha256', secret).update(rawBody).digest('base64');
  const a = Buffer.from(digest);
  const b = Buffer.from(hmacHeader || '');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
PHP
$raw = file_get_contents('php://input');
$calc = base64_encode(hash_hmac('sha256', $raw, $secret, true));
$ok = hash_equals($calc, $_SERVER['HTTP_X_SHOPIFY_HMAC_SHA256'] ?? '');
Python
import base64, hashlib, hmac

digest = base64.b64encode(hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()).decode()
ok = hmac.compare_digest(digest, request.headers.get('X-Shopify-Hmac-Sha256', ''))

Cause 1: base64, not hex

Most HMAC examples end with .digest('hex'). Shopify's header is base64. In PHP, the fourth argument of hash_hmac must be true (raw binary) before base64_encode.

Cause 2: the body was parsed

Hash the bytes of the request, before any JSON parsing. In Express use express.raw({ type: 'application/json' }) on the webhook route; in Next.js await req.text().

Cause 3: the wrong secret

Webhooks created by an app are signed with the app's client secret, not with an access token. Webhooks created in the Shopify admin (Settings → Notifications → Webhooks) are signed with the key shown on that page.

Frequently asked questions

Can I test without creating a real order?

Yes: Webhook Toolkit's signer builds a payload with a valid X-Shopify-Hmac-Sha256 for your secret and sends it to your handler, and the admin's “Send test notification” button delivers a sample to any URL.

Other webhook guides

Launch offer · −50 %

Debugging a webhook integration this week?

The 7-day Pass unlocks AI explanations and ready-to-paste handler code, 25 permanent URLs, 30-day history and the Relay tunnel to localhost. Pay once, no subscription.

€5 €2.50 once
One-time payment · no subscription · 14-day money-back · launch price until November 30
Shopify webhook HMAC (X-Shopify-Hmac-Sha256) verification failing — fix