Code Monkey home page Code Monkey logo

nextjs-shopify-auth's Introduction

@bluebeela/nextjs-shopify-auth

License: MIT

Authenticate your Next.js app with Shopify.

Sister module to @shopify/shopify-express and @shopify/koa-shopify-auth, but for nextjs.

Missing features

  • 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

Installation

$ npm install @bluebeela/nextjs-shopify-auth

Usage

This package exposes createShopifyAuth by default, authenticateShopifyPage, authenticateShopifyAPI, and NextShopifyApiRequest, as a named export.

import createShopifyAuth, {authenticateShopifyPage, authenticateShopifyAPI, NextShopifyApiRequest} from '@bluebeela/nextjs-shopify-auth';

createShopifyAuth

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);

in pages/api/example-api-route-you-want-to-protect.js

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" });
});

in pages/protected-page.js

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"}}
});

Required API routes

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

/api/shopify/auth/callback

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);
}

/api/shopify/auth/enable_cookies

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);
}

/api/shopify/auth/index

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);
}

/api/shopify/auth/inline

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);
}

/api/shopify/verify-token

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();
}

nextjs-shopify-auth's People

Contributors

bluebeel avatar c0 avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

nextjs-shopify-auth's Issues

Add support for `host` parameter used by Shopify App Bridge 2.0

Thanks for this awesome library! It has saved me a lot of time getting started with Shopify app development.

In case anyone is still working on this library...

The newer version 2 of Shopify App Bridge requires a new host parameter in the @shopify/app-bridge-react AppProvider config instead of the previous shopOrigin parameter. This host parameter isn't recognised or passed on by the authenticateShopifyPage() function.

Ideally this library would detect when the host parameter is present, store it in a cookie or browser storage, and provide in the result of authenticateShopifyPage() and it wherever else it's likely to be needed client-side. The parameter needs to be stored because it isn't available on every page load

For now I'm doing this โ˜๏ธ in my own app, but it would be nice to get it from the library.

See https://shopify.dev/apps/tools/app-bridge/migrating and https://shopify.dev/apps/tools/app-bridge/retrieve-the-host

Res.redirect is not a function

I am not able to get to the auth redirect.

[GET] /api/shopify/auth/inline?shop={shopName}
10:39:10:76
2021-02-17T18:39:10.830Z daf12db1-9f18-43d7-b793-b54ab871dea9 ERROR TypeError: res.redirect is not a function
at oAuthStart (/var/task/node_modules/@bluebeela/nextjs-shopify-auth/dist/auth/create-oauth-start.js:25:13)
at shopifyAuthInline (/var/task/.next/serverless/pages/api/shopify/auth/inline.js:268:9)
at apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:46:15)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async module.exports.COyd.webpack_exports.default (/var/task/.next/serverless/pages/api/shopify/auth/inline.js:187:11)

Infinite enable_cookies reload in chrome

Hi, not sure if there is some setting I'm missing in chrome or if this is an issue with the library but I keep getting infinite reloading on chrome when it tries to enable cookies by hitting the enable_cookies endpoint. I tried it with your demo app and the same problem occurs as well.

Thanks,
Jordan

Cookies required?

I wonder why are cookies required if Shopify is moving to cookie-less authentication?

Just curious.

Not getting redirected to my callback URL

First off, thanks for taking the time to put this together. I'm having trouble getting my app to redirect back to the permissions and install screen in Shopify.

My config.js

const shopifyAuthOptions = {
  apiKey: process.env.SHOPIFY_API_KEY,
  secret: process.env.SHOPIFY_API_SECRET,
  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/portal",
  scopes: ["read_products"],
  accessMode: "online",
  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);

export default shopify;

So far, so good. I want my app to use the /api/portal prefix. I've set up everything in /pages/api/portal according to the example project you provided.

I am a little confused when it comes to setting up the app in my Shopify Partner Portal.

For App URL I am using my base app URL, i.e. https://my-domain.vercel.app

For the Allowed Redirection URLs, this is the part I'm confused about.
Since all of the authentication is happening under the API routes should it be:
https://my-domain.vercel.app/api/portal/auth/callback or https://my-domain.vercel.app/auth/callback like the example?

I'm not sure what the prefix is actually doing to the routes.

Either one didn't work for me, I couldn't get the install screen to pop up.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.