Authenticate your Next.js app with Shopify.
Sister module to @shopify/shopify-express
and @shopify/koa-shopify-auth
, but for nextjs.
- Registering webhook
- Listening to webhook
A example app without the webhook for the Build a Shopify app with Node and React tutorial is available here
$ npm install @bluebeela/nextjs-shopify-auth
This package exposes createShopifyAuth
by default, authenticateShopifyPage
, authenticateShopifyAPI
, and NextShopifyApiRequest
, as a named export.
import createShopifyAuth, {authenticateShopifyPage, authenticateShopifyAPI, NextShopifyApiRequest} from '@bluebeela/nextjs-shopify-auth';
Returns a set of helpers that you will need to use in 4 different routes explained below.
const shopifyAuthOptions = {
// your shopify app api key
apiKey: process.env.SHOPIFY_API_KEY,
// your shopify app secret
secret: process.env.SHOPIFY_API_SECRET,
// your app url
appUrl: process.env.HOST,
// if specified, mounts the routes off of the given path
// eg. /api/shopify/auth, /api/shopify/auth/callback
// defaults to ""
prefix: "/api/shopify",
// scopes to request on the merchants store
scopes: ["read_products", "write_products"],
// set access mode, default is "online"
accessMode: "online",
// callback for when auth is completed
async afterAuth({
shopOrigin,
shopifyToken,
shopifyAssociatedUser,
req,
res,
}) {
console.log(
`We're authenticated on shop ${shopOrigin}: ${shopifyToken} with user ${JSON.stringify(
shopifyAssociatedUser
)}`
);
res.writeHead(302, { Location: `/` });
res.end();
},
};
const shopify = createShopifyAuth(shopifyAuthOptions);
Simply add the authenticateShopifyAPI middleware to your route to verify that the request is secure.
import { authenticateShopifyAPI } from "@bluebeela/nextjs-shopify-auth";
export default authenticateShopifyAPI(async function helloWorld(req, res) {
return await res.json({ hello: "world" });
});
Simply add the authenticateShopifyPage middleware to your route to verify that the request is secure.
// random page
import { authenticateShopifyPage } from "@bluebeela/nextjs-shopify-auth";
export const getServerSideProps = authenticateShopifyPage(async (ctx) => {
return { props: { hello: "world"}}
});
In a Next.js app, you will need to create these 5 routes:
- /api/shopify/auth/callback
- /api/shopify/auth/enable_cookies
- /api/shopify/auth/index
- /api/shopify/auth/inline
- /api/shopify/verify-token
Theses files will need the following content for the authentication and verification processes to work as expected
import shopify from "../../../../lib/shopify"; // lib is on the root dir
export default async function shopifyAuthCallback(req, res) {
const { oAuthCallback } = shopify;
await oAuthCallback(req, res);
}
import shopify from "../../../../lib/shopify"; // lib is on the root dir
export default async function shopifyAuthEnableCookies(req, res) {
const { enableCookies } = shopify;
await enableCookies(req, res);
}
import {
hasCookieAccess,
shouldPerformInlineOAuth,
grantedStorageAccess,
} from "@bluebeela/nextjs-shopify-auth";
import shopify from "../../../../lib/shopify"; // lib is on the root dir
export default async function shopifyAuthIndex(req, res) {
const {
enableCookiesRedirect,
oAuthStart,
topLevelOAuthRedirect,
requestStorageAccess,
} = shopify;
if (!hasCookieAccess(req.cookies)) {
await enableCookiesRedirect(req, res);
return;
}
if (!grantedStorageAccess(req.cookies)) {
await requestStorageAccess(req, res);
return;
}
if (shouldPerformInlineOAuth(req.cookies)) {
await oAuthStart(req, res);
return;
}
await topLevelOAuthRedirect(req, res);
}
import shopify from "../../../../lib/shopify"; // lib is on the root dir
export default async function shopifyAuthInline(req, res) {
const { oAuthStart } = shopify;
await oAuthStart(req, res);
}
This is a simple proxy route to avoid CORS issues we would face by hitting Shopify API from a different domain
export default async function verifyToken(req, res) {
const { shopOrigin, shopifyToken } = req.cookies;
const response = await fetch(
`https://${shopOrigin}/admin/metafields.json`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": shopifyToken,
},
},
);
res.status(response.status).end();
}