Shopify Automated Checks Failing

I have created my non-embedded public Shopify app. Now everything works on development store. Now when i am ready to submit it for app review, it fails on “Automated checks for common errors“.

My Authentication and Redirections Code is like this:

app.get(“/”, async (req, res) => {

try {

  **const shop = validateShop(req.query.shop);**

  **const { appKey, appSecret } = getAppCredentials(shop);**

  **const shopify = shopifyApi({**

     **apiKey: appKey,**

     **apiSecretKey: appSecret,**

     **scopes: \["read_products", "write_products", "read_themes", "write_themes", "read_script_tags", "write_script_tags", "read_orders", "write_orders", "read_customers", "unauthenticated_read_product_listings", "unauthenticated_write_checkouts"\],**

     **hostName: process.env.SHOPIFY_APP_URL.replace(/^https?:\\/\\//, ''),**

     **apiVersion: LATEST_API_VERSION,**

     **isEmbeddedApp: false**

  **});**



  **if (!shop) {**

     **return res.status(400).send("Missing Shop parameter");**

  **};**

const authRoute = await shopify.auth.begin({

     **shop,**

     **callbackPath: "/auth/callback",**

     **isOnline: false,**

     **rawRequest: req,**

     **rawResponse: res,**

  **});**

return res.redirect(authRoute);

} catch (error) {

  **return res.status(400).send(\`Authentication error: ${error.message}\`);**

}

**});

app.get(“/auth/callback”, async (req, res) => {**

try {

  **const storeName = validateShop(req.query.shop);**

  **const { appKey, appSecret } = getAppCredentials(storeName);**



  **const isValid = verifyHMAC(req.query, appSecret);**

  **if (!isValid) {**

     **logger.error("Invalid HMAC");**

     **return res.status(400).send("Invalid HMAC");**

  **}**

  

  **const shopify = shopifyApi({**

     **apiKey: appKey,**

     **apiSecretKey: appSecret,**

     **scopes: \["read_products", "write_products", "read_themes", "write_themes", "read_script_tags", "write_script_tags", "read_orders", "write_orders", "read_customers", "unauthenticated_read_product_listings", "unauthenticated_write_checkouts"\],**

     **hostName: process.env.SHOPIFY_APP_URL.replace(/^https?:\\/\\//, ''),**

     **apiVersion: LATEST_API_VERSION,**

     **isEmbeddedApp: false**

  **});**

**
**

  **const session = await shopify.auth.callback({**

     **rawRequest: req,**

     **rawResponse: res,**

  **});**



  **const { shop, accessToken } = session.session;**



  **if (!shop || !accessToken) {**

     **throw new Error("Missing shop or access token");**

  **}**



  **/\*\* now lets fetch the store info \*/**

  **const storeInfoURL = \`https://${shop}/admin/api/${LATEST_API_VERSION}/shop.json\`;**

  **const storeInfoRes = await fetch(storeInfoURL, {**

     **method: "GET",**

     **headers: {**

        **"X-Shopify-Access-Token": accessToken,**

        **"Content-Type": "application/json"**

     **}**

  **});**



  **if (!storeInfoRes.ok) {**

     **const storeInfoErrorRes = await storeInfoRes.text();**

     **throw new Error(\`Failed to fetch store info! status: ${storeInfoRes.status}\`);**

  **};**



  **const storeInfoData = await storeInfoRes.json();**



  **const email = storeInfoData.shop.email;**

  **const redirectUrl = \`${app_url}/Shopify.html?shop=${shop}&accessToken=${accessToken}&email=${email}\`;**

  **return res.redirect(redirectUrl);**

} catch (error) {

  **console.log(error);**

  **return res.status(500).send("Authentication failed. Try again, genius.");**

}

**});

**
Kindly help me out. Got stuck for 5 days.

My App is non-embedded public app.

Hey @Ansh_Goyal,

Based on the image you shared, this failure typically happens when your OAuth callback doesn’t follow the expected redirect pattern for your app type. For non-embedded apps, the authorization code grant documentation specifies redirecting to /?shop=${session.shop}&host=${encodeURIComponent(host)} after OAuth completes, following the documented format with only shop and host parameters.

I noticed you also have your access tokens directly in your redirect URL which may not be very secure ${app_url}/Shopify.html?shop=${shop}&accessToken=${accessToken}&email=${email}\ .

Instead of redirecting with the access token exposed (like ?accessToken=${accessToken}), store your session data securely on your server side and redirect to a clean URL with only the shop and host parameters. This pattern ensures both security compliance and proper app installation flow.

Hey @KyleG-Shopify

Now this is my code.

app.get(“/”, async (req, res) => {

console.log(“REquest hit”)

try {

  **const shop = validateShop(req.query.shop);**



  **/\*\* lets implement db logic \*/**

  **const result = await getStoreInfo(shop);**

  **console.log(result);**



  **if (result.code == 200) {**

     **const url = \`${app_url}/Shopify.html?shop=${shop}&email=${result.result.email}&accessToken=${result.result.access_token}\`;**

     **return res.redirect(url);**

  **}**



  **const { appKey, appSecret } = getAppCredentials(shop);**



  **const { host } = new URL(process.env.SHOPIFY_APP_URL);**

  **console.log(host, LATEST_API_VERSION);**



  **const shopify = shopifyApi({**

     **apiKey: appKey,**

     **apiSecretKey: appSecret,**

     **scopes: globalScopes,**

     **hostName: host,**

     **apiVersion: LATEST_API_VERSION,**

     **isEmbeddedApp: false**

  **});**



  **const authRoute = await shopify.auth.begin({**

     **shop: shopify.utils.sanitizeShop(shop, true),**

     **callbackPath: "/auth/callback",**

     **isOnline: false,**

     **rawRequest: req,**

     **rawResponse: res**

  **});**



  **return res.redirect(302, authRoute);**

} catch (error) {

  **logger.error(\`Authentication Failed: ${error.message}\`);**

  **return res.status(400).send(\`Authentication error: ${error.message}\`);**

}

});

app.get(“/auth/callback”, async (req, res) => {

console.log(“Callback Query:”, req.query);

try {

  **const storeName = validateShop(req.query.shop);**

  **const { appKey, appSecret } = getAppCredentials(storeName);**



  **const { host } = new URL(process.env.SHOPIFY_APP_URL);**



  **const shopify = shopifyApi({**

     **apiKey: appKey,**

     **apiSecretKey: appSecret,**

     **scopes: globalScopes,**

     **hostName: host,**

     **apiVersion: LATEST_API_VERSION,**

     **isEmbeddedApp: false**

  **});**

**
**

  **const session = await shopify.auth.callback({**

     **rawRequest: req,**

     **rawResponse: res,**

  **});**



  **const { shop, accessToken } = session.session;**



  **if (!accessToken) {**

     **throw new Error("Missing shop or access token");**

  **}**



  **await saveToDB(shop, accessToken);**



  **return res.redirect(\`/?shop=${shop}&host=${encodeURIComponent(host)}\`);

**

} catch (error) {

  **console.log(error);**

  **return res.status(500).send("Authentication failed. Try again, genius.");**

}

**});

But still its failing. I don’t know what’s going wrong. Please help !**

Looking at your app screenshot, I can see a few possible problems

  • Your app settings show “Use legacy install flow: false” but your code is trying to handle OAuth manually. Changing this to True should help, however, I would recommend if you can to use our template and switch to Shopify managed installations

  • Your App URL has :8080 in it, which looks like a development server. Production apps need clean URLs without port numbers.

  • In your code, I noticed you’re still putting access tokens directly in redirect URLs and not handling the host parameter correctly from the OAuth callback. The authorization code grant documentation shows the right way to handle redirects (Step 5) and process callback parameters (Step 3).

Hey @KyleG-Shopify Thanks Man ! Your 2nd point worked for me. Now my app is ready for submission. You really helped me a lot, glad to be guided by you.

You can mark this conversation as “solved” now.
Thanks !

Hey @Ansh_Goyal, glad we could sort that out! Best of luck on the rest of your submission!