Shopify / shopify-app-template-node

MIT License
888 stars 400 forks source link

[Express] Add offline access token hook on app installation #735

Closed Michael-Gibbons closed 2 years ago

Michael-Gibbons commented 2 years ago

Issue summary

Forgive me if I'm misunderstanding this

A very common use case for Shopify apps is to have webhooks, which require an access token. And in-app requests, which also require an access token.

To my understanding the correct access token for webhooks is an offline token since it requires long term access, and for user-scoped requests an online access token is preferred.

It would be nice to have some sort of hook which returns the permanent access token for an app so it can be saved in a database during the installation OAuth flow.

Expected behavior

There should be some hook to get the permanent access token for webhooks and other background processes

Actual behavior

Webhook requests are failing because they are using online access tokens which expire.

I'm happy to attempt to create a PR for this myself, I'm just unsure how to go about it.

Michael-Gibbons commented 2 years ago

Ah after reading some more oauth documentation I think I might have found a starting point. Will update with a PR soon

Michael-Gibbons commented 2 years ago

So I believe I figured out how to do it for the nextJS boiler, essentially the idea is to add a second shopifyAuth with offline like so

    shopifyAuth({
      accessMode: "offline",
      prefix: "/install",
      async afterAuth(ctx) {
        const { shop, accessToken, scope } = ctx.state.shopify;
        // store access tokens and register webhooks here
        ctx.redirect(`/auth?shop=${shop}`);
      },
    })

then whitelist /install/auth/callback as a redirect url in the app settings. so when the app is installed it goes through the install route, then after the offline access token is received it redirects to the regular auth route to generate an online access token for the user. At this moment I am unsure how to translate this into the express boiler.

Michael-Gibbons commented 2 years ago

Okay so after looking over the new auth flow this is what I gathered to be the process

if not authed -> redirect to /auth?shop={shop} -> if no signed oauth cookie -> redirect to /auth/toplevel?shop=${req.query.shop} -> depending on top level auth either redirect back to /auth or /auth/toplevel at this point all of the required auth information should be there so /auth will route to auth/callback then the callback is verified and you'll get either your online or offline access token determined by USE_ONLINE_TOKENS in server/index.js

So to follow the same logic as the NextJS solution we should be able to insert the offline middleman in /auth like so

  app.get("/auth", async (req, res) => {
    if (!req.signedCookies[app.get("top-level-oauth-cookie")]) {
      return res.redirect(`/auth/toplevel?shop=${req.query.shop}`);
    }

    const redirectUrl = await Shopify.Auth.beginAuth(
      req,
      res,
      req.query.shop,
      "/install/auth/callback",
      false
    );

    res.redirect(redirectUrl);
  });

  app.get("/install/auth/callback", async (req, res) => {
    if (!req.signedCookies[app.get("top-level-oauth-cookie")]) {
      return res.redirect(`/auth/toplevel?shop=${req.query.shop}`);
    }

    const session = await Shopify.Auth.validateAuthCallback(
      req,
      res,
      req.query
    );

    // STORE OFFLINE ACCESS TOKEN HERE, session.accessToken

    const redirectUrl = await Shopify.Auth.beginAuth(
      req,
      res,
      req.query.shop,
      "/auth/callback",
      app.get("use-online-tokens")
    );

    res.redirect(redirectUrl);
  });

I tested this and it does seem to be working. PR soon

Michael-Gibbons commented 2 years ago

PR here #736

unlocomqx commented 2 years ago

By default, I start with offline token then after getting it, I use the online access mode to get the online token. Something like this will work seamlessly https://github.com/unlocomqx/shopify-app-node/commit/6842707494350c84beb6a1b802d9611a0f6bf565

github-actions[bot] commented 2 years ago

This issue is stale because it has been open for 60 days with no activity. It will be closed if no further action occurs in 14 days.

github-actions[bot] commented 2 years ago

We are closing this issue because it has been inactive for a few months. This probably means that it is not reproducible or it has been fixed in a newer version. If it’s an enhancement and hasn’t been taken on since it was submitted, then it seems other issues have taken priority.

If you still encounter this issue with the latest stable version, please reopen using the issue template. You can also contribute directly by submitting a pull request– see the CONTRIBUTING.md file for guidelines

Thank you!