UNPKG

@shopify/shopify-app-express

Version:

Shopify Express Middleware - to simplify the building of Shopify Apps with Express

132 lines (112 loc) 3.41 kB
import {Request, Response} from 'express'; import { BotActivityDetected, CookieNotFound, privacyTopics, InvalidOAuthError, Session, Shopify, } from '@shopify/shopify-api'; import {AppConfigInterface} from '../config-types'; import {redirectToAuth} from '../redirect-to-auth'; import {AuthCallbackParams} from './types'; export async function authCallback({ req, res, api, config, }: AuthCallbackParams): Promise<boolean> { try { const callbackResponse = await api.auth.callback({ rawRequest: req, rawResponse: res, }); config.logger.debug('Callback is valid, storing session', { shop: callbackResponse.session.shop, isOnline: callbackResponse.session.isOnline, }); await config.sessionStorage.storeSession(callbackResponse.session); // If this is an offline OAuth process, register webhooks if (!callbackResponse.session.isOnline) { await registerWebhooks(config, api, callbackResponse.session); } // If we're completing an offline OAuth process, immediately kick off the online one if (config.useOnlineTokens && !callbackResponse.session.isOnline) { config.logger.debug( 'Completing offline token OAuth, redirecting to online token OAuth', {shop: callbackResponse.session.shop}, ); await redirectToAuth({req, res, api, config, isOnline: true}); return false; } res.locals.shopify = { ...res.locals.shopify, session: callbackResponse.session, }; config.logger.debug('Completed OAuth callback', { shop: callbackResponse.session.shop, isOnline: callbackResponse.session.isOnline, }); return true; } catch (error) { config.logger.error(`Failed to complete OAuth with error: ${error}`); await handleCallbackError(req, res, api, config, error); } return false; } async function registerWebhooks( config: AppConfigInterface, api: Shopify, session: Session, ) { config.logger.debug('Registering webhooks', {shop: session.shop}); const responsesByTopic = await api.webhooks.register({session}); for (const topic in responsesByTopic) { if (!Object.prototype.hasOwnProperty.call(responsesByTopic, topic)) { continue; } for (const response of responsesByTopic[topic]) { if (!response.success && !privacyTopics.includes(topic)) { const result: any = response.result; if (result.errors) { config.logger.error( `Failed to register ${topic} webhook: ${result.errors[0].message}`, {shop: session.shop}, ); } else { config.logger.error( `Failed to register ${topic} webhook: ${JSON.stringify( result.data, )}`, {shop: session.shop}, ); } } } } } async function handleCallbackError( req: Request, res: Response, api: Shopify, config: AppConfigInterface, error: Error, ) { switch (true) { case error instanceof InvalidOAuthError: res.status(400); res.send(error.message); break; case error instanceof CookieNotFound: await redirectToAuth({req, res, api, config}); break; case error instanceof BotActivityDetected: res.status(410); res.send(error.message); break; default: res.status(500); res.send(error.message); break; } }