UNPKG

@shopify/shopify-app-remix

Version:

Shopify Remix - to simplify the building of Shopify Apps with Remix

130 lines (126 loc) 5.33 kB
'use strict'; var shopifyApi = require('@shopify/shopify-api'); var respondToInvalidSessionToken = require('../../helpers/respond-to-invalid-session-token.js'); var getShopFromRequest = require('../../helpers/get-shop-from-request.js'); var invalidateAccessToken = require('../../helpers/invalidate-access-token.js'); require('isbot'); require('@remix-run/server-runtime'); var handleClientError = require('../helpers/handle-client-error.js'); var triggerAfterAuthHook = require('../helpers/trigger-after-auth-hook.js'); require('../../../types.js'); var ensureOfflineTokenIsNotExpired = require('../../../helpers/ensure-offline-token-is-not-expired.js'); class TokenExchangeStrategy { api; config; logger; constructor({ api, config, logger }) { this.api = api; this.config = config; this.logger = logger; } async respondToOAuthRequests(_request) { } async authenticate(request, sessionContext) { const { api, config, logger } = this; const { shop, session, sessionToken } = sessionContext; if (!sessionToken) throw new shopifyApi.InvalidJwtError(); if (!session || !session.isActive(undefined, ensureOfflineTokenIsNotExpired.WITHIN_MILLISECONDS_OF_EXPIRY)) { logger.info('No valid session found', { shop }); logger.info('Requesting offline access token', { shop }); const { session: offlineSession } = await this.exchangeToken({ request, sessionToken, shop, requestedTokenType: shopifyApi.RequestedTokenType.OfflineAccessToken, }); await config.sessionStorage.storeSession(offlineSession); let newSession = offlineSession; if (config.useOnlineTokens) { logger.info('Requesting online access token', { shop }); const { session: onlineSession } = await this.exchangeToken({ request, sessionToken, shop, requestedTokenType: shopifyApi.RequestedTokenType.OnlineAccessToken, }); await config.sessionStorage.storeSession(onlineSession); newSession = onlineSession; } logger.debug('Request is valid, loaded session from session token', { shop: newSession.shop, isOnline: newSession.isOnline, }); try { await this.handleAfterAuthHook({ api, config, logger }, newSession, request, sessionToken); } catch (errorOrResponse) { if (errorOrResponse instanceof Response) { throw errorOrResponse; } throw new Response(undefined, { status: 500, statusText: 'Internal Server Error', }); } return newSession; } return session; } handleClientError(request) { const { api, config, logger } = this; return handleClientError.handleClientErrorFactory({ request, onError: async ({ session, error }) => { if (error.response.code === 401) { logger.debug('Responding to invalid access token', { shop: getShopFromRequest.getShopFromRequest(request), }); await invalidateAccessToken.invalidateAccessToken({ config, logger }, session); respondToInvalidSessionToken.respondToInvalidSessionToken({ params: { config, api, logger }, request, }); } }, }); } async exchangeToken({ request, shop, sessionToken, requestedTokenType, }) { const { api, config, logger } = this; try { return await api.auth.tokenExchange({ sessionToken, shop, requestedTokenType, expiring: config.future.expiringOfflineAccessTokens, }); } catch (error) { if (error instanceof shopifyApi.InvalidJwtError || (error instanceof shopifyApi.HttpResponseError && error.response.code === 400 && error.response.body?.error === 'invalid_subject_token')) { throw respondToInvalidSessionToken.respondToInvalidSessionToken({ params: { api, config, logger }, request, retryRequest: true, }); } throw new Response(undefined, { status: 500, statusText: 'Internal Server Error', }); } } async handleAfterAuthHook(params, session, request, sessionToken) { const { config } = params; await config.idempotentPromiseHandler.handlePromise({ promiseFunction: () => { return triggerAfterAuthHook.triggerAfterAuthHook(params, session, request, this); }, identifier: sessionToken, }); } } exports.TokenExchangeStrategy = TokenExchangeStrategy; //# sourceMappingURL=token-exchange.js.map