We are experiencing issues with HMAC verification for Shopify webhooks in our app.
The verification is consistently failing even with webhooks that we believe are valid.
Technical Details:
- Using Python with FastAPI framework
- Implementing standard HMAC-SHA256 verification
- Current implementation:
- Get raw request body bytes via request.body()
- Get HMAC from X-Shopify-Hmac-Sha256 header
- Calculate HMAC using client secret and request body
- Compare using hmac.compare_digest()
Troubleshooting Steps Taken:
- Verified we’re using correct client secret
- Tested with both raw bytes and encoded strings
- Tried multiple base64 encoding/decoding approaches
- Tested with mock webhooks to localhost
- Referenced Shopify documentation and forum implementations
Request:
- Could you verify our HMAC calculation approach is correct?
- Can you provide a test webhook with known:
- Client secret
- Request payload
- Expected HMAC signature
- Which secret should we be used? App client secret or store secret?
- Any additional debugging guidance would be helpful
I would recommend checking out this post to see if the steps here help Hmac doesn't match (python)
How are you creating your webhook?
1 Like
Hi @JordanFinners,
Thanks for your reply. However, our webhook was created via an app, not a store. Therefore, it is not the same as the post you mentioned.
Hey,
Its the same principal and code that will authenticate the webhook so worth checking out and ensuring your code matches the approach. The only difference will be the token you are using to validate the HMAC.
If its public app

Or private/developed app

Hi @JordanFinners , I’m running into a similar issue. I’m unable to verify the hmac for the mandatory compliance webhooks for my public app. I’ve used the Client secret
for my app.
I’m using Python’s FastAPI to handle the webhook -
async def verify_shopify_webhook(
request: Request,
x_shopify_hmac_sha256: str = Header(None, alias="X-Shopify-Hmac-Sha256"),
):
hmac_header = x_shopify_hmac_sha256
if not hmac_header:
logger.error("No HMAC header found in request")
raise HTTPException(status_code=401, detail="No HMAC header found")
logger.debug(f"Verifying Shopify webhook with HMAC: {hmac_header}")
body = await request.body()
logger.debug(f"Verifying Shopify webhook with Body: {body}")
logger.debug(f"Body length: {len(body)}")
logger.debug(f"Body as string: {body.decode('utf-8', errors='ignore')}")
webhook_secret = "" #Client secret of the app
logger.debug(f"Using webhook secret: {webhook_secret}")
# Calculate HMAC using base64 encoding
digest_bytes = hmac.new(
webhook_secret.encode("utf-8"), body, hashlib.sha256
).digest()
calculated_hmac = base64.b64encode(digest_bytes).decode('utf-8')
logger.debug(f"Calculated HMAC: {calculated_hmac}")
logger.debug(f"Expected HMAC: {hmac_header}")
# Verify HMAC signature
if not hmac.compare_digest(calculated_hmac, hmac_header):
logger.warning(f"Invalid HMAC signature. Calculated: {calculated_hmac}, Expected: {hmac_header}")
raise HTTPException(status_code=401, detail="Invalid HMAC signature")
logger.info("Shopify webhook verified")
Any ideas on what could be the issue ?
Yeah you’re doing some extra encoding/decoding from the looks of it.
I would checkout the example provided by the Shopify team. Hmac doesn't match (python) - #4 by Dave-Shopify
Then just change the method for data to be the await body()
you have here.
Also ensure nothing else in fast api is messing with the body, as you want the raw bytes of the request