Webhook HMAC Verification
Definition
When Shopify delivers a webhook over HTTPS, the request carries an HMAC-SHA256 signature. The receiver recomputes it and trusts the payload only when the two values match.
- Where the signature is: the X-Shopify-Hmac-SHA256 header, Base64 encoded
- What goes into it: the app's client secret as the key, and the raw request body as the message
- The check: compare your computed value against the header, and reject the request without reading the body if they differ
- Where it applies: HTTPS delivery only. Deliveries to Google Cloud Pub/Sub and Amazon EventBridge don't need it, because the cloud delivery path is closed by design
The same mechanism protects other places where Shopify posts to your server, such as Shopify Flow action endpoints.
Background
A webhook endpoint is a public URL, and anyone who learns the address can post to it. An endpoint that skips verification is an open door for forged order or refund events. In e-commerce, webhooks trigger inventory allocation, loyalty points, syncing to back-office systems and customer emails, so a forged event turns directly into real damage.
The usual implementation mistake is the raw body. Most web frameworks parse incoming JSON automatically, and re-serializing the parsed object changes whitespace and key order, so the signature never matches. The byte sequence has to be captured before anything interprets it. The comparison itself should use a timing-safe function rather than plain string equality. One operational note: after rotating the app's client secret, it can take up to an hour before signatures are generated with the new value.
Verification proves that a request came from Shopify. It does not prove that it arrives only once. Guard against retries and duplicate deliveries by rejecting repeats with X-Shopify-Webhook-Id, or by making the processing idempotent.
Flagship's Involvement
Verification is part of our standard webhook implementation, both in the Shopify apps we publish and in the integration layers we build for clients. Including it in our app boilerplate from the start avoids the gaps that appear when each project reimplements it. On enterprise projects we sometimes route deliveries through Pub/Sub or EventBridge instead, and there the guarantee comes from the delivery path and cloud-side permissions rather than from an HMAC check. Duplicate and missed deliveries are a separate problem, which we handle with idempotent processing and reconciliation jobs that poll on a schedule.