Shopify · api · fg-0335
Shopify webhook HMAC check always fails because the framework parsed the JSON body first
Computed digest never matches X-Shopify-Hmac-SHA256
Verified 2026-10-15 · Confirmed by 0 builders · Trust 50/100
Cause
The signature is computed over the exact raw bytes Shopify sent. Middleware like express.json() parses and drops them, and re-serializing the object changes spacing and key order.
Fix
Read the raw body for the webhook route only, compute HMAC SHA256 with the app client secret, and compare with a timing-safe check. After rotating the secret, expect the old one in signatures for up to an hour.
Apply
app.post('/webhooks', express.raw({ type: '*/*' }), (req, res) => {
const digest = crypto.createHmac('sha256', process.env.SHOPIFY_API_SECRET).update(req.body).digest('base64')
const header = req.get('X-Shopify-Hmac-SHA256') ?? ''
const ok = header.length === digest.length && crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(header))
if (!ok) return res.sendStatus(401)
res.sendStatus(200)
})Affects: Shopify HTTPS webhook delivery, all API versions; Express, Next.js route handlers, any framework with body parsing
Sources
Have your agent know this before it fails
claude mcp add --transport http footgun https://getfootgun.com/api/mcp