# Fix Shopify webhook HMAC validation failing

## TL;DR
HMAC validation fails when you compute the digest over the wrong bytes or with the wrong secret. Use the raw request body and the app's webhook secret, compute HMAC-SHA256, and compare with the X-Shopify-Hmac-Sha256 header using a constant-time compare. Parsed JSON bodies break the digest.

## The error
```text
Shopify webhook handler error
HMAC validation failed: computed digest does not match X-Shopify-Hmac-Sha256
```

## Use this skill
Agent? Search Vectle for this error:
```bash
curl -s "https://vectle.com/api/v1/search?q=shopify webhook hmac validation failed"
```

## Fix it

### Step 1: Read the raw body

```bash
Ensure your route receives the raw bytes. Do not let JSON middleware parse it first on the webhook path.
```

Expected: Your handler sees the untouched payload bytes.

### Step 2: Get the correct webhook secret

```bash
From your Shopify app settings, copy the webhook secret (the API secret key for the app).
```

Expected: You have the current secret value.

### Step 3: Compute HMAC-SHA256 over the raw body

```bash
Use your language's HMAC with SHA256, keyed by the secret, over the raw body bytes, then base64-encode it.
```

Expected: The computed digest is a base64 string.

### Step 4: Compare with the header in constant time

```bash
Compare your digest with the X-Shopify-Hmac-Sha256 header using a timing-safe compare.
```

Expected: They match for genuine Shopify webhooks.

### Step 5: Test with a real webhook

```bash
Trigger a test webhook from the Shopify admin.
```

Expected: Validation passes and the event processes.

## When this applies

- Shopify webhooks fail HMAC validation
- Webhooks worked and broke after a framework change
- You are building the webhook receiver for the first time

## When it doesn't

- No webhooks arrive at all (check the subscription and URL)
- Validation passes but processing fails (check your handler)
- You rotated the app secret (update the stored secret too)

## Compatibility

Shopify webhooks. Any stack; HMAC-SHA256 is the algorithm.

## Variant phrasings

### shopify hmac sha256 mismatch webhook

Same failure. Raw bytes plus correct secret is the whole fix.

### x-shopify-hmac-sha256 invalid

An invalid header value with correct code usually means the secret is stale after rotation.

### shopify webhook signature failed after deploy

Deploys that add global JSON parsing middleware are the classic regression.

## Why it happens

Shopify signs the raw payload bytes with your app secret. Anything that changes the bytes, parsing to JSON and re-encoding, trimming whitespace, or a wrong secret, produces a different digest. The comparison is exact by design.

## Edge cases

- Some proxies normalize request bodies; terminate TLS at your app or verify behind the proxy carefully
- Test webhooks from the admin use the same signing; they are safe to validate against
- Log the topic and a hash of the payload on failure, never the full payload with customer data

## If it still fails

- Reproduce with one API call in isolation, outside the agent, to separate platform issues from agent issues.
- Check the platform status page and changelog; OAuth and webhook behaviors change without warning.
- Capture the full request and response with timestamps for the vendor ticket, redacting credentials.
- Test in a second workspace or sandbox to rule out workspace-specific policy blocks.
- If the integration is business-critical, build the fallback now: cached data, a manual trigger, or a second provider.

## Prevention

- Store OAuth credentials in a secrets manager with rotation reminders.
- Build the reconnect flow before you need it; every integration gets revoked eventually.
- Log token ages so expiring grants are visible ahead of time.
- Keep a sandbox integration for testing config changes.
- Document the required scopes per integration so reinstalls request the right ones.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_OFzyOhWSZ5PMvb2nioWIGQ
