Using accessMode: offline, seeing issue where loadCallback has id as offline_undefined instead of offline_shop-name.myshopify.com.
This happens when I call app API's from Shopify storefront through script tag.
Expected behavior
id coming in loadCallback shouldn't be offline_undefined
Actual behavior
Error: CustomSessionStorage failed to load a session. Error Details: TypeError: Cannot read property 'id' of null
at SessionStorageError.ShopifyError [as constructor] (/Users/green/shopify/jwt-app/node_modules/@shopify/shopify-api/dist/error.js:13:28)
at new SessionStorageError (/Users/green/shopify/jwt-app/node_modules/@shopify/shopify-api/dist/error.js:172:42)
at CustomSessionStorage.<anonymous> (/Users/green/shopify/jwt-app/node_modules/@shopify/shopify-api/dist/auth/session/storage/custom.js:46:31)
at step (/Users/green/shopify/jwt-app/node_modules/@shopify/shopify-api/node_modules/tslib/tslib.js:143:27)
at Object.throw (/Users/green/shopify/jwt-app/node_modules/@shopify/shopify-api/node_modules/tslib/tslib.js:124:57)
at rejected (/Users/green/shopify/jwt-app/node_modules/@shopify/shopify-api/node_modules/tslib/tslib.js:115:69)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
Code
server.js
```
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";
import { MongoClient } from "mongodb";
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
async function storeCallback(session) {
// Store session in DB.
return true;
}
async function loadCallback(id) {
// Incoming id coming as offline_undefined
// Load session from DB
return session;
}
async function deleteCallback(id) {
// Delete from DB.
}
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
)
});
const ACTIVE_SHOPIFY_SHOPS = {};
MongoClient.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(async connection => {
console.info(`Successfully connected to Mongo`);
const mongodb = connection;
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET,
scopes: [SCOPES],
accessMode: "offline",
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
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}`);
},
})
);
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;
// 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);
}
});
server.use(require("./api"));
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
router.get("(.*)", verifyRequest({ accessMode: "offline" }), handleRequest); // Everything else must have sessions
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
});
```
Issue summary
Using
accessMode: offline
, seeing issue whereloadCallback
has id asoffline_undefined
instead ofoffline_shop-name.myshopify.com
.This happens when I call app API's from Shopify storefront through script tag.
Expected behavior
id
coming inloadCallback
shouldn't beoffline_undefined
Actual behavior
Code
server.js
``` 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"; import { MongoClient } from "mongodb"; dotenv.config(); const port = parseInt(process.env.PORT, 10) || 8081; const dev = process.env.NODE_ENV !== "production"; const app = next({ dev, }); const handle = app.getRequestHandler(); async function storeCallback(session) { // Store session in DB. return true; } async function loadCallback(id) { // Incoming id coming as offline_undefined // Load session from DB return session; } async function deleteCallback(id) { // Delete from DB. } 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 ) }); const ACTIVE_SHOPIFY_SHOPS = {}; MongoClient.connect(MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true, }).then(async connection => { console.info(`Successfully connected to Mongo`); const mongodb = connection; app.prepare().then(async () => { const server = new Koa(); const router = new Router(); server.keys = [Shopify.Context.API_SECRET_KEY]; server.use( createShopifyAuth({ apiKey: SHOPIFY_API_KEY, secret: SHOPIFY_API_SECRET, scopes: [SCOPES], accessMode: "offline", async afterAuth(ctx) { // Access token and shop available in ctx.state.shopify const { shop, accessToken, scope } = ctx.state.shopify; ACTIVE_SHOPIFY_SHOPS[shop] = scope; 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}`); }, }) ); 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; // 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); } }); server.use(require("./api")); router.get("(/_next/static/.*)", handleRequest); // Static content is clear router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear router.get("(.*)", verifyRequest({ accessMode: "offline" }), handleRequest); // Everything else must have sessions server.use(router.allowedMethods()); server.use(router.routes()); server.listen(port, () => { console.log(`> Ready on http://localhost:${port}`); }); }); }); ```