All Projects → Shopify → koa-shopify-auth

Shopify / koa-shopify-auth

Licence: MIT license
DEPRECATED Middleware to authenticate a Koa application with Shopify

Programming Languages

javascript
184084 projects - #8 most used programming language
typescript
32286 projects

Projects that are alternatives of or similar to koa-shopify-auth

shopify-node-react-app
Shopify paid app in Node.js & React.js that connects to a store and lets merchants select products to automatically discount them in the Shopify admin interface.
Stars: ✭ 29 (-64.63%)
Mutual labels:  koa, shopify
shopify-react-astro
A demo of a Shopify site using Astro and React.
Stars: ✭ 103 (+25.61%)
Mutual labels:  shopify
Blog
若川的博客—学习源码整体架构系列8篇,前端面试高频源码,微信搜索「若川视野」关注我,长期交流学习~
Stars: ✭ 234 (+185.37%)
Mutual labels:  koa
bunjil
A GraphQL bastion server with schema merging, authentication and authorization with Policy Based Access Control
Stars: ✭ 25 (-69.51%)
Mutual labels:  koa
Atlas Of Thrones
An interactive "Game of Thrones" map powered by Leaflet, PostGIS, and Redis.
Stars: ✭ 253 (+208.54%)
Mutual labels:  koa
pupflare
A webpage proxy that request through Chromium (puppeteer) - can be used to bypass Cloudflare anti bot / anti ddos on any application (like curl)
Stars: ✭ 183 (+123.17%)
Mutual labels:  koa
Koa Proxy
Proxy middleware for koa
Stars: ✭ 221 (+169.51%)
Mutual labels:  koa
koa-subdomain
Simple and lightweight Koa middleware to handle multilevel and wildcard subdomains
Stars: ✭ 23 (-71.95%)
Mutual labels:  koa
numvalidate
Phone number validation REST API
Stars: ✭ 54 (-34.15%)
Mutual labels:  koa
koa-plus
The Koa framework extended for APIs. Optimized for security, scalability, and productivity.
Stars: ✭ 17 (-79.27%)
Mutual labels:  koa
Shopify-Serverless-Starter-App
Shopify Serverless Starter Application built on Serverless Framework and Polaris UI (React.js)
Stars: ✭ 56 (-31.71%)
Mutual labels:  shopify
Javascript Boilerplate
Node.js+Koa.js+PostgreSQL+React.js+Webpack+Mocha+Makefile, a starter kit for new apps
Stars: ✭ 253 (+208.54%)
Mutual labels:  koa
koa-ip-filter
koa middleware to filter request IPs or custom ID with glob patterns, array, string, regexp or matcher function. Support custom 403 Forbidden message and custom ID.
Stars: ✭ 23 (-71.95%)
Mutual labels:  koa
Strapi Sdk Javascript
🔌 Official JavaScript SDK for APIs built with Strapi.
Stars: ✭ 247 (+201.22%)
Mutual labels:  koa
shopify-node-express-app
Simple Shopify app with Express and Node.js that connects to a Shopify store via OAuth.
Stars: ✭ 20 (-75.61%)
Mutual labels:  shopify
Koa Websocket
Light wrapper around Koa providing a websocket middleware handler that is koa-route compatible.
Stars: ✭ 224 (+173.17%)
Mutual labels:  koa
teapot
Utilities for working with HTTP status codes, errors, and more
Stars: ✭ 14 (-82.93%)
Mutual labels:  koa
Ajaxinate
🎡 Ajax pagination plugin for Shopify themes
Stars: ✭ 107 (+30.49%)
Mutual labels:  shopify
vue-koa2-login
🍥 Vue + Koa2 实现前后端注册登录流程
Stars: ✭ 23 (-71.95%)
Mutual labels:  koa
chatroom
💬chat
Stars: ✭ 56 (-31.71%)
Mutual labels:  koa

DEPRECATED @shopify/koa-shopify-auth

NOTE: this repo is no longer maintained. Prefer the official Node API.

If you're still wanting to use Koa, see simple-koa-shopify-auth for a potential community solution.

Build Status License: MIT npm version

Middleware to authenticate a Koa application with Shopify.

Sister module to @shopify/shopify-express, but simplified.

Features you might know from the express module like the webhook middleware and proxy will be presented as their own packages instead.

Warning: versions prior to 3.1.68 vulnerable to reflected XSS

Versions prior to 3.1.68 are vulnerable to a reflected XSS attack. Please update to the latest version to protect your app.

Installation

This package builds upon the Shopify Node Library, so your app will have access to all of the library's features as well as the Koa-specific middlewares this package provides.

$ yarn add @shopify/koa-shopify-auth

Usage

This package exposes shopifyAuth by default, and verifyRequest as a named export. To make it ready for use, you need to initialize the Shopify Library and then use that to initialize this package:

import shopifyAuth, {verifyRequest} from '@shopify/koa-shopify-auth';
import Shopify, {ApiVersion} from '@shopify/shopify-api';

// Initialize the library
Shopify.Context.initialize({
  API_KEY: 'Your API_KEY',
  API_SECRET_KEY: 'Your API_SECRET_KEY',
  SCOPES: ['Your scopes'],
  HOST_NAME: 'Your HOST_NAME (omit the https:// part)',
  API_VERSION: ApiVersion.October20,
  IS_EMBEDDED_APP: true,
  // More information at https://github.com/Shopify/shopify-node-api/blob/main/docs/issues.md#notes-on-session-handling
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

shopifyAuth

Returns an authentication middleware taking up (by default) the routes /auth and /auth/callback.

app.use(
  shopifyAuth({
    // if specified, mounts the routes off of the given path
    // eg. /shopify/auth, /shopify/auth/callback
    // defaults to ''
    prefix: '/shopify',
    // set access mode, default is 'online'
    accessMode: 'offline',
    // callback for when auth is completed
    afterAuth(ctx) {
      const {shop, accessToken} = ctx.state.shopify;

      console.log('We did it!', accessToken);

      ctx.redirect('/');
    },
  }),
);

/auth

This route starts the oauth process. It expects a ?shop parameter and will error out if one is not present. To install it in a store just go to /auth?shop=myStoreSubdomain.

/auth/callback

You should never have to manually go here. This route is purely for shopify to send data back during the oauth process.

verifyRequest

Returns a middleware to verify requests before letting them further in the chain.

Note: if you're using a prefix for shopifyAuth, that prefix needs to be present in the paths for authRoute and fallbackRoute below.

app.use(
  verifyRequest({
    // path to redirect to if verification fails
    // defaults to '/auth'
    authRoute: '/foo/auth',
    // path to redirect to if verification fails and there is no shop on the query
    // defaults to '/auth'
    fallbackRoute: '/install',
    // which access mode is being used
    // defaults to 'online'
    accessMode: 'offline',
    // if false, redirect the user to OAuth. If true, send back a 403 with the following headers:
    //  - X-Shopify-API-Request-Failure-Reauthorize: '1'
    //  - X-Shopify-API-Request-Failure-Reauthorize-Url: '<auth_url_path>'
    // defaults to false
    returnHeader: true,
  }),
);

Migrating from cookie-based authentication to session tokens

Versions prior to v4 of this package used cookies to store session information for your app. However, internet browsers have been moving to block 3rd party cookies, which creates issues for embedded apps.

If you have an app using this package, you can migrate from cookie-based authentication to session tokens by performing a few steps:

  • Upgrade your @shopify/koa-shopify-auth dependency to v4+
  • Update your server as per the Usage instructions to properly initialize the @shopify/shopify-api library
  • If you are using accessMode: 'offline' in shopifyAuth, make sure to pass the same value in verifyRequest
  • Install @shopify/app-bridge-utils in your frontend app
  • In your frontend app, replace fetch calls with authenticatedFetch from App Bridge Utils

Note: the backend steps need to be performed to fully migrate your app to v4, even if your app is not embedded.

You can learn more about session tokens in our authentication tutorial. Go to the frontend changes section under Setup for instructions and examples on how to update your frontend code.

Example app

This example will enable you to quickly set up the backend for a working development app. Please read the Gotchas session below to make sure you are ready for production use.

import 'isomorphic-fetch';

import Koa from 'koa';
import Router from 'koa-router';
import shopifyAuth, {verifyRequest} from '@shopify/koa-shopify-auth';
import Shopify, {ApiVersion} from '@shopify/shopify-api';

// Loads the .env file into process.env. This is usually done using actual environment variables in production
import dotenv from 'dotenv';
dotenv.config();

const port = parseInt(process.env.PORT, 10) || 8081;

// initializes the library
Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SHOPIFY_APP_SCOPES,
  HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/^https:\/\//, ''),
  API_VERSION: ApiVersion.October20,
  IS_EMBEDDED_APP: true,
  // More information at https://github.com/Shopify/shopify-node-api/blob/main/docs/issues.md#notes-on-session-handling
  SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};

const app = new Koa();
const router = new Router();
app.keys = [Shopify.Context.API_SECRET_KEY];

// Sets up shopify auth
app.use(
  shopifyAuth({
    async afterAuth(ctx) {
      const {shop, accessToken} = ctx.state.shopify;
      ACTIVE_SHOPIFY_SHOPS[shop] = true;

      // Your app should handle the APP_UNINSTALLED webhook to make sure merchants go through OAuth if they reinstall it
      const response = await Shopify.Webhooks.Registry.register({
        shop,
        accessToken,
        path: '/webhooks',
        topic: 'APP_UNINSTALLED',
        webhookHandler: async (topic, shop, body) =>
          delete ACTIVE_SHOPIFY_SHOPS[shop],
      });

      if (!response['APP_UNINSTALLED'].success) {
        console.log(
          `Failed to register APP_UNINSTALLED webhook: ${response['APP_UNINSTALLED'].result}`,
        );
      }

      // Redirect to app with shop parameter upon auth
      ctx.redirect(`/?shop=${shop}`);
    },
  }),
);

router.get('/', async (ctx) => {
  const shop = ctx.query.shop;

  // If 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 {
    // Load app skeleton. Don't include sensitive information here!
    ctx.body = '🎉';
  }
});

router.post('/webhooks', async (ctx) => {
  try {
    await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
    console.log(`Webhook processed, returned status code 200`);
  } catch (error) {
    console.log(`Failed to process webhook: ${error}`);
  }
});

// Everything else must have sessions
router.get('(.*)', verifyRequest(), async (ctx) => {
  // Your application code goes here
});

app.use(router.allowedMethods());
app.use(router.routes());
app.listen(port, () => {
  console.log(`> Ready on http://localhost:${port}`);
});

Gotchas

Session

The provided MemorySessionStorage class may not be scalable for production use. You can implement your own strategy by creating a class that implements a few key methods. Learn more about how the Shopify Library handles sessions.

Testing locally

By default this app requires that you use a myshopify.com host in the shop parameter. You can modify this to test against a local/staging environment via the myShopifyDomain option to shopifyAuth (e.g. myshopify.io).

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].