Custom session storage generates multiple session IDs from single app install
See original GitHub issueI’m not 100% sure this is a bug, but it seems to be unexpected behaviour so I need to ask…
I built a Node shopify app using the shopify CLI (recent version).
In my server.js file, I’m initialising the Shopify context to use custom session storage, like so:
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,
SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(
storeCallback,
loadCallback,
deleteCallback
),
});
I used the guide to define the 3 required callback methods. I’m using Firebase for my custom storage solution, so my code looks like this:
// https://github.com/Shopify/shopify-node-api/blob/main/docs/usage/customsessions.md
/*
The storeCallback takes in the Session, and sets it in Firestore
This callback is used for BOTH saving new Sessions and updating existing Sessions
Returns a Firebase write result if the session can be stored
*/
const storeCallback = async (session) => {
console.log(
`Custom session storage storeCallback fired with id [${session.id}]`
);
try {
await db
.doc(`app-sessions/${session.id}`)
.set(JSON.parse(JSON.stringify(session)), { merge: true });
return true;
} catch (err) {
throw new Error(err);
}
};
/*
The loadCallback takes in the id, and tries to retrieve the session data from Firestore
If a stored session exists, it's returned
Otherwise, return undefined
*/
const loadCallback = async (id) => {
console.log(`Custom session storage loadCallback fired with id [${id}]`);
try {
const sessionSnapshot = await db
.doc(`app-sessions/${id}`)
.get();
if (!sessionSnapshot.exists) {
console.log(`Custom session storage session id [${id}] does not exist`);
return undefined;
}
const session = sessionSnapshot.data();
if (!session) {
console.log(`Custom session storage session id [${id}] no data`);
return undefined;
}
return session;
} catch (err) {
throw new Error(err);
}
};
/*
The deleteCallback takes in the id, and attempts to delete the session from Firestore
If the session can be deleted, return true,
otherwise, return false
*/
const deleteCallback = async (id) => {
console.log(`Custom session storage deleteCallback fired with id [${id}]`);
try {
const sessionSnapshot = await db
.doc(`app-sessions/${id}`)
.get();
if (!sessionSnapshot.exists) {
console.log(`Custom session storage session id [${id}] does not exist`);
return false;
}
await db.doc(`app-sessions/${id}`).delete();
return true;
} catch (err) {
throw new Error(err);
}
};
What I would expect to see when a user installs the app is a single session object being stored in the DB.
What I actually see is 2 session objects being stored, each with a different session ID.
Here is the relevant portion of my logs from a single app install on my development store at the point where the custom session methods are being executed:
2021-07-28T16:36:38.847238+00:00 app[web.1]: Custom session storage loadCallback fired with id [3b8ecc7b-2f8b-401e-9ef0-dc4dee1a0c6c]
2021-07-28T16:36:39.399084+00:00 app[web.1]: Custom session storage storeCallback fired with id [my-test-store.myshopify.com_75101241518]
2021-07-28T16:36:39.503989+00:00 app[web.1]: Custom session storage storeCallback fired with id [3b8ecc7b-2f8b-401e-9ef0-dc4dee1a0c6c]
2021-07-28T16:36:39.602216+00:00 app[web.1]: Custom session storage loadCallback fired with id [3b8ecc7b-2f8b-401e-9ef0-dc4dee1a0c6c]
2021-07-28T16:36:39.696272+00:00 app[web.1]: after auth...
Note:
- Both session objects have an identical
session.accessToken
andsession.onlineAccessInfo.associatedUser.session
, but differentsession.id
andsession.expires
value.
So my questions:
- Why is
storeCallback
firing twice, with 2 different session IDs even though as a user, I’ve only started one session from one app install? - When a user loads the app, I’m planning on inspecting the
session.expires
to decide whether to send the user back into the oauth flow (I think that is the correct implementation but stop me if I’m wrong). With 2 different sessions for the same user, which one should I inspect? I’ve tested locally and ended up with 4 session objects from the same app/install, which is really odd! I’m guessing that if I answer question 1, question 2 becomes irrelevant.
Thanks in advance for the help 😃
Issue Analytics
- State:
- Created 2 years ago
- Reactions:13
- Comments:27 (2 by maintainers)
Hey folks! Thanks for raising this. This is a know issue we’re currently working on. Sorry we don’t have an immediate solution to suggest, but hopefully this bug will be gone soon.
Hi, I’m also having the same issue that getting two sessions, When I save it in the MongoDB with NodeJS it will record 2 sessions. And someone can explain how deleteCallback and loadCallback work when those functions fire?