shopify-api-js icon indicating copy to clipboard operation
shopify-api-js copied to clipboard

How to save the accessToken with CustomSessionStorage?

Open charle-connoringold opened this issue 3 years ago • 8 comments
trafficstars

Overview/summary

First of all, I really like the project and thank you for the work you've put into this! I just have one question which I can't seem to find the answer to anywhere in the docs and it's really bugging me. So I've set up auth routes and custom session storage as I've put below (basically identical to the docs). My question is this, how with the shopify-node-api do I save the session and how do I access it?

Shopify.Context.initialize({
  API_KEY: SHOPIFY_API_KEY,
  API_SECRET_KEY: SHOPIFY_API_SECRET,
  SCOPES: ["read_customers", "write_customers"],
  HOST_NAME: HOST.replace(/https:\/\//, ""),
  IS_EMBEDDED_APP: true,
  ApiVersion: "January22",
  SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(storeCallBack, loadCallBack, deleteCallBack)
})

app.get('/auth/callback', async (req, res) => {
  try {
    const session = await Shopify.Auth.validateAuthCallback(
      req,
      res,
      req.query as unknown as AuthQuery,
    );
    // How do I save you?
    console.log(session.accessToken);
  } catch (error) {
    console.error(error); // in practice these should be handled more gracefully
  }
  return res.redirect(`/?host=${req.query.host}&shop=${req.query.shop}`); // wherever you want your user to end up after OAuth completes
});

...

Motivation

Struggling to kind the answer in the current docs or anywhere.

charle-connoringold avatar Mar 21 '22 09:03 charle-connoringold

validateAuthCallback calls SESSION_STORAGE.storeCallback (or rather, SESSION_STORAGE.storeSession, which then calls storeCallback) under the hood -- so assuming your CustomSessionStorage is implemented properly, it's already being done!

See here: https://github.com/Shopify/shopify-node-api/blob/2527af569d9e5be95848081c086f5cd19cf632d7/src/auth/oauth/oauth.ts#L200

bishpls avatar Mar 21 '22 22:03 bishpls

Thanks, So then accessing the session is just a simple case of const session = await Shopify.Utils.loadCurrentSession(req, res) ?

It would be really great to have a full working example in the docs where they use CustomSessionStorage.

charle-connoringold avatar Mar 22 '22 15:03 charle-connoringold

@charle-connoringold

Yes, but no, but yes, but kind of?

That's the INTENDED functionality, but it can get a little wacky if you're using offline access token sessions, due to some unresolved issues.

See here: https://github.com/Shopify/shopify-node-api/pull/272

Long story short: for a standalone (non-embedded) app using offline sessions, loadCurrentSession is currently borked, and loadOfflineSession is not a clean drop-in replacement due to the fact that it doesn't validate the request. I've written up the details here: https://github.com/Shopify/shopify-node-api/pull/199#issuecomment-1021733105

bishpls avatar Mar 22 '22 23:03 bishpls

Any Fixed on this issue ?

Sky-bits avatar Sep 14 '22 12:09 Sky-bits

Any Fixed on this issue ?

I ended up using the new MongoDBSessionStorage session storage:

const { API_KEY, API_SECRET_KEY, SCOPES, SHOP, HOST, HOST_SCHEME } = process.env

Shopify.Context.initialize({
  API_KEY,
  API_SECRET_KEY,
  SCOPES: SCOPES.split(','),
  HOST_NAME: HOST.replace(/https?:\/\//, ''),
  HOST_SCHEME,
  IS_EMBEDDED_APP: true,
  API_VERSION: LATEST_API_VERSION, // all supported versions are available, as well as "unstable" and "unversioned"
  SESSION_STORAGE: new Shopify.Session.MongoDBSessionStorage(
    new URL(process.env.DB_HOST),
    process.env.DB_NAME,
  ),
})

Which automatically stores the session when validateAuthCallback is called. And then calling loadCurrentSession will load the session for you.

I really wish this was documented better but to be fair, it does say:

"As mentioned in the previous sections, you can use the OAuth methods to create both offline and online sessions. Once the process is completed, the session will be stored as per your Context.SESSION_STORAGE strategy, and can be retrieved with the below utilities.

To load a session, you can use the following method. You can load both online and offline sessions from the current request / response objects. await Shopify.Utils.loadCurrentSession(request, response, isOnline); If you need to load a session for a background job, you can get offline sessions directly from the shop. await Shopify.Utils.loadOfflineSession(shop); Note: the loadOfflineSession method does not perform any validations on the shop parameter. You should avoid calling it from user inputs or URLs."

charle-connoringold avatar Sep 14 '22 13:09 charle-connoringold

@charle-connoringold Thanks Lot for the Answers. how do i get the Shop object ? ` Shopify.Utils.loadOfflineSession(shop); ^

ReferenceError: shop is not defined ` in App back-end i am doing the background job

here my issue https://github.com/Shopify/shopify-api-node/issues/493

Sky-bits avatar Sep 14 '22 13:09 Sky-bits

@sanjay-ios-io In my case, it's just an environment variable in a .env file, and the value is apps-testing-connor.myshopify.com but you could query the DB for the shop.

charle-connoringold avatar Sep 14 '22 15:09 charle-connoringold

@charle-connoringold Thanks for the answer Shop URL i am getting into my code Dynamically args.shop this was the my active shop args args.shop == mytestingshop.myshopify.com

const session = new Shopify.Utils.loadOfflineSession(args.shop); const client = new Shopify.Clients.Graphql(session.shop, session.accessToken);

Error Getting Client side on console

  {
  "message": "Missing access token when creating GraphQL client",
  
} 

Server side Error

  @shopify/shopify-api/dist/auth/oauth/oauth.js:207
            var authHeader = request.headers.authorization;
                                             ^

TypeError: Cannot read properties of undefined (reading 'authorization')  

Sky-bits avatar Sep 15 '22 04:09 Sky-bits

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

github-actions[bot] avatar Nov 15 '22 02:11 github-actions[bot]

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!

github-actions[bot] avatar Nov 30 '22 02:11 github-actions[bot]