{"version":3,"file":"token-exchange.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/token-exchange.ts"],"sourcesContent":["import {\n  HttpResponseError,\n  InvalidJwtError,\n  RequestedTokenType,\n  Session,\n} from '@shopify/shopify-api';\n\nimport {AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n  respondToInvalidSessionToken,\n  invalidateAccessToken,\n  getShopFromRequest,\n} from '../../helpers';\nimport {handleClientErrorFactory, triggerAfterAuthHook} from '../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport {WITHIN_MILLISECONDS_OF_EXPIRY} from '../../../helpers';\n\nimport {\n  AuthorizationStrategy,\n  SessionContext,\n  OnErrorOptions,\n  AuthStrategyFactory,\n} from './types';\n\nexport const createTokenExchangeStrategy: AuthStrategyFactory<any> = <\n  Config extends AppConfigArg,\n>(\n  params: BasicParams<Config['future']>,\n): AuthorizationStrategy => {\n  const {api, config, logger} = params;\n\n  async function exchangeToken({\n    request,\n    shop,\n    sessionToken,\n    requestedTokenType,\n  }: {\n    request: Request;\n    shop: string;\n    sessionToken: string;\n    requestedTokenType: RequestedTokenType;\n  }): Promise<{session: Session}> {\n    try {\n      console.log(\n        'config.future.expiringOfflineAccessTokens',\n        config.future.expiringOfflineAccessTokens,\n      );\n      return await api.auth.tokenExchange({\n        sessionToken,\n        shop,\n        requestedTokenType,\n        expiring: config.future.expiringOfflineAccessTokens,\n      });\n    } catch (error) {\n      if (\n        error instanceof InvalidJwtError ||\n        (error instanceof HttpResponseError &&\n          error.response.code === 400 &&\n          error.response.body?.error === 'invalid_subject_token')\n      ) {\n        throw respondToInvalidSessionToken({\n          params: {api, config, logger},\n          request,\n          retryRequest: true,\n        });\n      }\n\n      throw new Response(undefined, {\n        status: 500,\n        statusText: 'Internal Server Error',\n      });\n    }\n  }\n\n  async function handleAfterAuthHook(\n    session: Session,\n    request: Request,\n    sessionToken: string,\n  ) {\n    await config.idempotentPromiseHandler.handlePromise({\n      promiseFunction: () => {\n        return triggerAfterAuthHook(params, session, request, {\n          authenticate,\n          handleClientError,\n        });\n      },\n      identifier: sessionToken,\n    });\n  }\n\n  async function authenticate(\n    request: Request,\n    sessionContext: SessionContext,\n  ): Promise<Session> {\n    const {shop, session, sessionToken} = sessionContext;\n\n    if (!sessionToken) throw new InvalidJwtError();\n\n    if (\n      !session ||\n      !session.isActive(undefined, WITHIN_MILLISECONDS_OF_EXPIRY)\n    ) {\n      logger.info('No valid session found', {shop});\n      logger.info('Requesting offline access token', {shop});\n      const {session: offlineSession} = await exchangeToken({\n        request,\n        sessionToken,\n        shop,\n        requestedTokenType: RequestedTokenType.OfflineAccessToken,\n      });\n\n      await config.sessionStorage!.storeSession(offlineSession);\n\n      let newSession = offlineSession;\n\n      if (config.useOnlineTokens) {\n        logger.info('Requesting online access token', {shop});\n        const {session: onlineSession} = await exchangeToken({\n          request,\n          sessionToken,\n          shop,\n          requestedTokenType: RequestedTokenType.OnlineAccessToken,\n        });\n\n        await config.sessionStorage!.storeSession(onlineSession);\n        newSession = onlineSession;\n      }\n\n      logger.debug('Request is valid, loaded session from session token', {\n        shop: newSession.shop,\n        isOnline: newSession.isOnline,\n      });\n\n      try {\n        await handleAfterAuthHook(newSession, request, sessionToken);\n      } catch (errorOrResponse) {\n        if (errorOrResponse instanceof Response) {\n          throw errorOrResponse;\n        }\n\n        throw new Response(undefined, {\n          status: 500,\n          statusText: 'Internal Server Error',\n        });\n      }\n\n      return newSession;\n    }\n\n    return session!;\n  }\n\n  function handleClientError(request: Request): HandleAdminClientError {\n    return handleClientErrorFactory({\n      request,\n      onError: async ({session, error}: OnErrorOptions) => {\n        if (error.response.code === 401) {\n          logger.debug('Responding to invalid access token', {\n            shop: getShopFromRequest(request),\n          });\n          await invalidateAccessToken({config, api, logger}, session);\n\n          respondToInvalidSessionToken({\n            params: {config, api, logger},\n            request,\n          });\n        }\n      },\n    });\n  }\n\n  return {\n    authenticate,\n    handleClientError,\n  };\n};\n"],"names":[],"mappings":"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"}