shopify-api-js
shopify-api-js copied to clipboard
How to save the accessToken with CustomSessionStorage?
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.
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
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
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
Any Fixed on this issue ?
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 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
@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 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')
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.
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!