Oauthshopify

Topic summary

A developer is blocked during Shopify’s app review process at the HMAC verification step. The core issue: the install button is disabled during review, preventing the OAuth flow from completing.

Key Problem:

  • HMAC verification typically occurs after app installation
  • During app review, installation cannot proceed, creating a catch-22 situation
  • Developer is uncertain whether this is a misunderstanding of the review process or a technical implementation issue

Technical Context:

  • Code shows OAuth authorization flow with popup window
  • Requests multiple Shopify scopes (orders, products, customers, inventory, etc.)
  • Redirect URI points to localhost:3000/integrations
  • Implementation includes interval polling to detect OAuth callback

Code Quality Note:
The provided code snippet appears corrupted or obfuscated in sections, making full technical assessment difficult.

Status: Awaiting community guidance on proper HMAC verification approach during Shopify app review, or clarification on review process expectations.

Summarized with AI on November 10. AI used: claude-sonnet-4-5-20250929.

Hello, I’m stuck in the app review process, specifically in the last step where HMAC verification is required. I’m unsure how to proceed with it. According to my understanding, HMAC verification should be performed after the client installs the app. However, during the app review, the install button is disabled, preventing me from progressing further.

Could you guys help me identify the issue or clarify if I’m misunderstanding something? Here’s my code for reference.

const openPopup = () => {
const clientID= ’ client id here’;
const redirectUri = ‘http://localhost:3000/integrations’;
const permissionUrl = /oauth/authorize?client_id=${clientID}&scope=read_checkouts,read_shopify_payments_payouts,read_all_orders,read_content,write_content,read_themes,write_themes,read_products,write_products,read_customers,write_customers,read_orders,write_orders,read_script_tags,write_script_tags,read_fulfillments,write_fulfillments,read_shipping,write_shipping,read_inventory,write_inventory&redirect_uri=${redirectUri};

let setLoading = true;
let windowObjectReference = null;
let previousUrl = null;
let interval = null;
const strWindowFeatures = “toolbar=no, menubar=no, width=1360, height=700, top=100, left=108”;

if (windowObjectReference === null || windowObjectReference.closed) {
windowObjectReference = window.open([https://${shop-domaine}.myshopify.com/admin](https://alriqastore.myshopify.com/admin)${permissionUrl}, “”, strWindowFeatures);
var timer = setInterval(function () {
if (windowObjectReference.closed) {
setLoading = false;
clearInterval(timer);
}
}, 1000);
} else if (previousUrl !== url) {
windowObjectReference = window.open(url, “”, strWindowFeatures);
windowObjectReference.focus();
var timer = setInterval(function() {
if (windowObjectReference.closed) {
setLoading = false;
clearInterval(timer);
}
}, 1000);
}
interval = window.setInterval(() => {
try {
let temp = windowObjectReference.location;
if
(temp.hostname === “localhost” || temp.hostname === “app.live-metrics.io”) {
window.clearInterval(interval);
var result = ‘{’;
var test = temp.href.split(“?”)[1];
for (let i in test.split(“&”)) {
let item = test.split(“&”)[i];
result = result + "${item.split("=")[0]}":"${item.split("=")[1]}";
if (i < (test.split(“&”).length - 1)) result = result + “,”
}
result = result + ‘}’
try {
JSON.parse(result);
integrateShopify(result);
windowObjectReference.close();
setLoading(false);
setReachedFinalStep(true);
setRefetch(!refetch);
} catch (e) {
windowObjectReference.close();
SweetAlert.fire({
title: props.t(“Shopify Integration Error”),
icon: props.t(“error”),
text: props.t(“There was a technical error when integrating your store. Please contact our support at: support@livemetrics.tn”)
}).then((val) => {
setLoading(false);
})
}
}
} catch (error) {
}
}, 1000);
previousUrl = url;
};