App reviews, troubleshooting, and recommendations
Hello, I sent my app for review about 3 weeks ago and received a list of things to fix.
The app is a Remix-Run app, built by using the Shopify documentation all along.
The Shopify API version was 2024-01 but I changed it to 2024-04 today in hope it will help me fix the problem, which wasn't the case eventually.
After I fixed the issues that were mentioned on the review, I tried to submit the fixes but the "Submit Fixes" button is disabled, while in the preliminary steps mentioned in the distribution screen, it mentions that the "Implement an HMAC signature to verify webhooks" section is failing.
I'm trying to fix this issue for the past 2 days without any success.
On some post I read that when using Remix-run, the
const { topic } = await authenticate.webhook(
request
);
should take care of the webhook verification.
On other posts I read that I need to pull out something like that:
https://remix.run/docs/en/main/guides/resource-routes#webhooks
while in the Shopify docs: https://remix.run/docs/en/main/guides/resource-routes#webhooks there are nice examples for other PHP, Rubi and Python, but not for Node.js or Remix-Run.
So I tried all sorts of ways to make it work, but when I click the Re-Run button on the distribution screen, I keep failing on the "Implement an HMAC signature to verify webhooks" section.
Can someone please elaborate and be specific on the steps I need to do to make this test pass?
It's so frustrating that the documentation is lacking of information while this is a blocker for any progress.
The Secret I'm using is correct, so that's not the problem.
Thanks in advance!
The HMAC implementation is specifically for GDPR webhooks. The three GDPR webhooks rely on a separate webhook validation mechanism than the regular ones. I have two examples of the verifyHMAC middleware that I use in production that you can work with.
Express: verifyHmac.js
Next.js: verifyHmac.js
Hey @kinngh and thanks for your response 🙂
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 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?
So first I would recommend learning how Remix works before you go ahead and build anything with it, or you're gonna be running into walls and it's going to get quiet frustrating.
As far as webhook verification is concerned, and I don't know what endpoints are you testing, but the automated test makes a GDPR request, not any other webhook requests. You wanna look into your GDPR webhooks and how you're managing those or the automated test is almost always going to fail
Same issue here, we need help from shopify people, documentation is really unclear and we have no logs to know what's wrong.
I also configured the mandatory webhooks with hmac verification but it's not working.
Did anyone find a solution please ?
The Remix docs have most of the solution here: https://remix.run/docs/en/main/guides/resource-routes#webhooks
I just had to adjust it slightly to be
// Validate the webhook signature
const signature = request.headers.get("x-shopify-hmac-sha256");
const generatedSignature = crypto
.createHmac("SHA256", process.env.SHOPIFY_API_SECRET!)
.update(rawPayload)
.digest("base64");
if (signature !== generatedSignature) {
return json({ message: "Invalid signature" }, 401);
}
Most of the places I was reading said to JSON.stringify the payload but finally I found that the hashes matched without that for some reason.
But the important part is actually that the authenticate.webhook(request) part consumes the request.body so you need to clone the request _before_ you authenticate.
// The authentication middleware consumes the request body, so we need to clone it
// before it's consumed. We need the raw payload to validate the webhook signature.
const reqClone = request.clone()
const rawPayload = await reqClone.text();
thank you, thank you, thank you!
I used the payload from the authentication at first, but some webhooks calculated a wrong hmac and did not verify, so I found that I needed to use the raw body instead. But I all the posts about this use some middlewear that I didn't understand. This was a much better and understandable solution for me so thank you!
Thank you it's working for me as well !
Like to note, that after implementing this correctly, Shopify check may still fail.
If so, restart your app, "npm run dev". Then in another terminal do, "npm run shopify app deploy", to deploy the app to shopify.
Doing this will make sure Shopify will perform the check with the correct up to date URLs instead of the outdated URLs that change everytime you do "npm run dev". I believe Shopify performs the test on the URLs from the latest deploy.
URLs from "shopify.app.toml"
Starting a B2B store is a big undertaking that requires careful planning and execution. W...
By JasonH Sep 23, 2024By investing 30 minutes of your time, you can unlock the potential for increased sales,...
By Jacqui Sep 11, 2024We appreciate the diverse ways you participate in and engage with the Shopify Communi...
By JasonH Sep 9, 2024