Have your say in Community Polls: What was/is your greatest motivation to start your own business?
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Embedded app fails OAuth when deployed

Embedded app fails OAuth when deployed

jeffgolota
Visitor
1 0 0

Hi, I'm an intern that is currently developing an embedded Shopify app for the company I'm working for and during development on local testing it works fine but once I pushed the final changes to the repository and the company deployed the app, the installation fails and gives an "Invalid OAuth callback" error when I try to install it on a test store with the deployed URL listed in the app details.

The app gets a list of products and their information

The app is deployed on an EC2 Instance, a Linux system with NPM if that is relevant to solve the problem.

The app's domain is https://shopify-app.stage.iqm.services/

If any other information is needed I can provide

My server.js file is shown below.

import "@babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "@shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "@shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";

dotenv.config();
var token = '';
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
  dev,
});
const handle = app.getRequestHandler();

Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SCOPES.split(","),
  HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
  API_VERSION: ApiVersion.October20,
  IS_EMBEDDED_APP: true,
  // This should be replaced with your preferred storage strategy
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(async () => {
  const server = new Koa();
  var url = '';
  const router = new Router();
  server.keys = [Shopify.Context.API_SECRET_KEY];
  server.use(
    createShopifyAuth({
      async afterAuth(ctx) {
        // Access token and shop available in ctx.state.shopify
        const { shop, accessToken, scope } = ctx.state.shopify;
        console.log("ACCESS TOKEN = " + accessToken);
        setToken(accessToken);

        const host = ctx.query.host;
        ACTIVE_SHOPIFY_SHOPS[shop] = scope;
        const response = await Shopify.Webhooks.Registry.register({
          shop,
          accessToken,
          path: "/webhooks",
          topic: "APP_UNINSTALLED",
          webhookHandler: async (topic, shop, body) =>
            delete ACTIVE_SHOPIFY_SHOPS[shop],
        });
        if (!response.success) {
          console.log(
            `Failed to register APP_UNINSTALLED webhook: ${response.result}`
          );
        }

        // Redirect to app with shop parameter upon auth
        ctx.redirect(`/?shop=${shop}&host=${host}`);
      },
    })
  );

  const handleRequest = async (ctx) => {
    await handle(ctx.req, ctx.res);
    ctx.respond = false;
    ctx.res.statusCode = 200;
  };

  router.get("/", async (ctx) => {
    const shop = ctx.query.shop;
    url = shop;
    // This shop hasn't been seen yet, go through OAuth to create a session
    if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
      ctx.redirect(`/auth?shop=${shop}`);
    } else {
      await handleRequest(ctx);
    }
  });

  router.post("/webhooks", async (ctx) => {
    try {
      await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
      console.log(`Webhook processed, returned status code 200`);
    } catch (error) {
      console.log(`Failed to process webhook: ${error}`);
    }
  });

  router.post(
    "/graphql",
    verifyRequest({ returnHeader: true }),
    async (ctx, next) => {
      await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
    }
  );

  router.get("(/_next/static/.*)", handleRequest); // Static content is clear
  router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
  router.get('/api/products', async (ctx) => {
    try {
      var token = getToken();
      let productsURL = "https://" + url + "/admin/api/2021-04/products.json";
      const results = await fetch(productsURL, {
        headers: {
          "X-Shopify-Access-Token": token,

        },
      })
        .then(response => response.json())
        .then(json => {

          return [json, url];
        });
      ctx.body = {
        status: 'success',
        data: results
      };
    } catch (err) {
      console.log("Fetch Failed");
      console.log(err)
    }
  })
  router.get('/shopname', async (ctx) => {
    return url;
  })
  router.get("(.*)", verifyRequest(), handleRequest); // Everything else must have sessions

  server.use(router.allowedMethods());
  server.use(router.routes());
  server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`);
  });
});

function getToken() {
  return token;
}
function setToken(newToken) {
  token = newToken;
}
Replies 6 (6)

Avi_Ben_Zaken
Shopify Partner
18 0 6
Click to expand...
Hey, have a similar issue, have you pinned the problem?
mamoumb
Shopify Partner
6 0 0

any answer? same case as well..

test6A
Shopify Partner
23 0 13

Any solutions? I'm facing the same issue

mamoumb
Shopify Partner
6 0 0

My issue was that 'next' was not properly set up in dev nor in production. In production environment I had to set up next.config.js so that api Key and Host url can be provided. I also had to feed my Provider config (_app.js) with api key,host and shop
(shop must me provided to AppBridge e.g "<MyProvider Component={Component} {...pageProps} shop={shop} />") parameters..

noahfromfolds
Shopify Partner
17 2 6

Also have the exact same issue. If anyone has a solution it would be great. My app works in development but not in production for some reason with the auth.

Founder / CEO of Folds Page Builder | Available for free at: https://apps.shopify.com/folds
noahfromfolds
Shopify Partner
17 2 6

Okay figured out my issue. I was using the wrong API secret on the server, I accidentally copied the one for my development app instead. 

Founder / CEO of Folds Page Builder | Available for free at: https://apps.shopify.com/folds