How do I implement HMAC signature for webhook verification in a Remix-Run app?

Topic summary

Developers are struggling to pass Shopify’s automated HMAC signature verification test for webhooks in Remix-Run apps, which blocks app distribution approval. The “Submit Fixes” button remains disabled when this check fails.

Key Technical Points:

  • The standard authenticate.webhook(request) method consumes the request body, preventing proper HMAC verification
  • GDPR webhooks (the three mandatory compliance webhooks) require separate HMAC validation beyond regular webhook authentication
  • The Shopify documentation lacks Node.js/Remix-specific examples, only providing PHP, Ruby, and Python implementations

Working Solution:
Clone the request before authentication to preserve the raw payload:

const reqClone = request.clone()
const rawPayload = await reqClone.text();

Then verify using the raw payload (not JSON.stringify):

const signature = request.headers.get("x-shopify-hmac-sha256");
const generatedSignature = crypto
  .createHmac("SHA256", process.env.SHOPIFY_API_SECRET)
  .update(rawPayload)
  .digest("base64");

Additional Tip:
After implementing the fix, restart the dev server and run npm run shopify app deploy to ensure Shopify tests against current URLs rather than outdated development URLs.

Multiple developers confirmed this approach successfully passes the automated verification check.

Summarized with AI on October 24. AI used: claude-sonnet-4-5-20250929.

Hey @kinngh and thanks for your response :slightly_smiling_face:
I’m not sure how to add a middleware to a remix project, I’m kind of new to Remix.run and to Shopify as well.

That being said, I did implement a function that checks the hmac (not using Shopify’s authenticate.webhook). and I when test it on real webhooks coming from Shopify, the signature is equal to the calculated signature and that works well.
When I’m calling the webhooks endpoint directly (not through the Shopify), I do get a 401 error (both when I use Shopify’s authenticate.webhook and when I calculate the signature myself and comparing it to the x-shopify-hmac-sha256 I receive).
But in both cases when I click the Re-Run button on the appStore review screen (Run a automated check for common errors section) I still get a failure on the Implement an [HMAC signature](https://shopify.dev/docs/apps/webhooks/configuration/https#step-5-verify-the-webhook) to verify webhooks section, and I have no idea why.

I mean - isn’t the all idea of that requirement to block webhook calls that are not coming from Shopify? if that’s the case, than I would think the test should be successful, but it’s not.

I guess I’m missing something… any ideas?