{"version":3,"file":"HeadlessB2BMagicLinkClient.mjs","sources":["../../../../../../../../core/src/HeadlessClients/b2b/HeadlessB2BMagicLinkClient.ts"],"sourcesContent":["import { DisabledDFPProtectedAuthProvider, IDFPProtectedAuthProvider } from '../../DFPProtectedAuthProvider';\nimport { INetworkClient } from '../../NetworkClient';\nimport { IPKCEManager } from '../../PKCEManager';\nimport {\n  B2BMagicLinksInviteOptions,\n  B2BMagicLinksInviteResponse,\n  ResponseCommon,\n  StytchProjectConfigurationInput,\n} from '../../public';\nimport {\n  B2BMagicLinkLoginOrSignupOptions,\n  B2BMagicLinkLoginOrSignupResponse,\n  B2BMagicLinksAuthenticateOptions,\n  B2BMagicLinksAuthenticateResponse,\n  B2BMagicLinksDiscoveryAuthenticateOptions,\n  B2BMagicLinksDiscoveryAuthenticateResponse,\n  B2BMagicLinksEmailDiscoverySendOptions,\n  B2BMagicLinksEmailDiscoverySendResponse,\n  IHeadlessB2BMagicLinksClient,\n} from '../../public/b2b/magicLinks';\nimport { IB2BSubscriptionService } from '../../SubscriptionService';\nimport { validateInDev } from '../../utils/dev';\n\ntype DynamicConfig = Promise<{\n  pkceRequiredForEmailMagicLinks: boolean;\n}>;\n\nconst DefaultDynamicConfig = Promise.resolve({\n  pkceRequiredForEmailMagicLinks: false,\n});\n\nexport class HeadlessB2BMagicLinksClient<TProjectConfiguration extends StytchProjectConfigurationInput>\n  implements IHeadlessB2BMagicLinksClient<TProjectConfiguration>\n{\n  email: {\n    invite: (data: B2BMagicLinksInviteOptions) => Promise<B2BMagicLinksInviteResponse>;\n    loginOrSignup: (data: B2BMagicLinkLoginOrSignupOptions) => Promise<ResponseCommon>;\n    discovery: {\n      send: (data: B2BMagicLinksEmailDiscoverySendOptions) => Promise<B2BMagicLinksEmailDiscoverySendResponse>;\n    };\n  };\n\n  authenticate: (\n    data: B2BMagicLinksAuthenticateOptions,\n  ) => Promise<B2BMagicLinksAuthenticateResponse<TProjectConfiguration>>;\n\n  discovery: {\n    authenticate: (\n      data: B2BMagicLinksDiscoveryAuthenticateOptions,\n    ) => Promise<B2BMagicLinksDiscoveryAuthenticateResponse<TProjectConfiguration>>;\n  };\n\n  constructor(\n    private _networkClient: INetworkClient,\n    private _subscriptionService: IB2BSubscriptionService<TProjectConfiguration>,\n    private _pkceManager: IPKCEManager,\n    private _passwordResetPKCEManager: IPKCEManager,\n    private _config: DynamicConfig = DefaultDynamicConfig,\n    private dfpProtectedAuth: IDFPProtectedAuthProvider = DisabledDFPProtectedAuthProvider(),\n  ) {\n    this.email = {\n      invite: async (data: B2BMagicLinksInviteOptions): Promise<B2BMagicLinksInviteResponse> => {\n        validateInDev('stytch.magicLinks.email.invite', data, {\n          email_address: 'string',\n          invite_redirect_url: 'optionalString',\n          invite_template_id: 'optionalString',\n          name: 'optionalString',\n          locale: 'optionalString',\n          roles: 'optionalStringArray',\n          invite_expiration_minutes: 'optionalNumber',\n        });\n\n        return this._networkClient.fetchSDK<B2BMagicLinksInviteResponse>({\n          url: '/b2b/magic_links/email/invite',\n          body: data,\n          method: 'POST',\n        });\n      },\n      loginOrSignup: async (data: B2BMagicLinkLoginOrSignupOptions): Promise<ResponseCommon> => {\n        validateInDev('stytch.magicLinks.email.loginOrSignup', data, {\n          email_address: 'string',\n          organization_id: 'string',\n          login_redirect_url: 'optionalString',\n          login_template_id: 'optionalString',\n          signup_redirect_url: 'optionalString',\n          signup_template_id: 'optionalString',\n          locale: 'optionalString',\n          login_expiration_minutes: 'optionalNumber',\n          signup_expiration_minutes: 'optionalNumber',\n        });\n\n        const pkce_code_challenge = await this.getCodeChallenge();\n        const requestBody = {\n          ...data,\n          pkce_code_challenge,\n        };\n        return this._networkClient.fetchSDK<B2BMagicLinkLoginOrSignupResponse>({\n          url: '/b2b/magic_links/email/login_or_signup',\n          body: requestBody,\n          method: 'POST',\n        });\n      },\n      discovery: {\n        send: async (\n          data: B2BMagicLinksEmailDiscoverySendOptions,\n        ): Promise<B2BMagicLinksEmailDiscoverySendResponse> => {\n          validateInDev('stytch.magicLinks.email.discovery.send', data, {\n            email_address: 'string',\n            discovery_redirect_url: 'optionalString',\n            login_template_id: 'optionalString',\n            locale: 'optionalString',\n            discovery_expiration_minutes: 'optionalNumber',\n          });\n\n          const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();\n          const pkce_code_challenge = await this.getCodeChallenge();\n          const requestBody = {\n            ...data,\n            pkce_code_challenge,\n            dfp_telemetry_id,\n            captcha_token,\n          };\n          return this._networkClient.retriableFetchSDK<B2BMagicLinksEmailDiscoverySendResponse>({\n            url: '/b2b/magic_links/email/discovery/send',\n            body: requestBody,\n            method: 'POST',\n            retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP,\n          });\n        },\n      },\n    };\n\n    this.authenticate = this._subscriptionService.withUpdateSession(async (data: B2BMagicLinksAuthenticateOptions) => {\n      validateInDev('stytch.magicLinks.authenticate', data, {\n        magic_links_token: 'string',\n        session_duration_minutes: 'number',\n        locale: 'optionalString',\n      });\n\n      // When a user resets their password with PKCE turned on, they create a pkPair in the 'passwords' namespace.\n      // However, when the user gets the reset password email, they have the option to log in without a password.\n      // This redirects them to the magic link authenticate flow, which automatically looks for the pkce code_verifier\n      // in the 'magic_links' namespace, breaking the flow. Unfortunately we won't know for sure in the eml authenticate call\n      // whether or not the user is coming from a password reset flow. To handle this, we have to try to authenticate with\n      // both the 'passwords' and 'magic_links' code_verifiers.\n      const passwordResetPKPair = await this._passwordResetPKCEManager.getPKPair();\n\n      let resp: B2BMagicLinksAuthenticateResponse<TProjectConfiguration> | null = null;\n\n      if (passwordResetPKPair?.code_verifier) {\n        try {\n          resp = await this.handlePKCEForAuthenticate(this._passwordResetPKCEManager, data);\n        } catch (e) {\n          if ((e as Error).message.includes('pkce')) {\n            // If pkce-related error, fall back to magic links code_verifier\n            // eslint-disable-next-line no-console\n            console.log(\n              'Authenticate with passwords pkce namespace failed. Falling back to authenticate with magic_links namespace.',\n            );\n          } else {\n            throw e;\n          }\n        }\n      }\n\n      if (!resp) {\n        resp = await this.handlePKCEForAuthenticate(this._pkceManager, data);\n      }\n\n      return resp;\n    });\n\n    this.discovery = {\n      authenticate: this._subscriptionService.withUpdateSession(\n        async (\n          data: B2BMagicLinksDiscoveryAuthenticateOptions,\n        ): Promise<B2BMagicLinksDiscoveryAuthenticateResponse<TProjectConfiguration>> => {\n          validateInDev('stytch.magicLinks.discovery.authenticate', data, {\n            discovery_magic_links_token: 'string',\n          });\n\n          const pkPair = await this._pkceManager.getPKPair();\n\n          const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();\n\n          const requestBody = {\n            pkce_code_verifier: pkPair?.code_verifier,\n            dfp_telemetry_id,\n            captcha_token,\n            ...data,\n          };\n          const resp = await this._networkClient.retriableFetchSDK<\n            B2BMagicLinksDiscoveryAuthenticateResponse<TProjectConfiguration>\n          >({\n            url: '/b2b/magic_links/discovery/authenticate',\n            body: requestBody,\n            method: 'POST',\n            retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP,\n          });\n\n          this._pkceManager.clearPKPair();\n\n          return resp;\n        },\n      ),\n    };\n  }\n\n  private async getCodeChallenge(): Promise<string | undefined> {\n    const { pkceRequiredForEmailMagicLinks } = await this._config;\n    if (!pkceRequiredForEmailMagicLinks) {\n      return undefined;\n    }\n    let keyPair = await this._pkceManager.getPKPair();\n    if (keyPair) {\n      return keyPair.code_challenge;\n    }\n    keyPair = await this._pkceManager.startPKCETransaction();\n    return keyPair.code_challenge;\n  }\n\n  private async handlePKCEForAuthenticate(\n    pkceManager: IPKCEManager,\n    data: B2BMagicLinksAuthenticateOptions,\n  ): Promise<B2BMagicLinksAuthenticateResponse<TProjectConfiguration>> {\n    const pkPair = await pkceManager.getPKPair();\n\n    const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();\n\n    const requestBody = {\n      pkce_code_verifier: pkPair?.code_verifier,\n      dfp_telemetry_id,\n      captcha_token,\n      intermediate_session_token: (await this._subscriptionService.getIntermediateSessionToken()) || undefined,\n      ...data,\n    };\n    const resp = await this._networkClient.retriableFetchSDK<B2BMagicLinksAuthenticateResponse<TProjectConfiguration>>({\n      url: '/b2b/magic_links/authenticate',\n      body: requestBody,\n      method: 'POST',\n      retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP,\n    });\n\n    pkceManager.clearPKPair();\n\n    return resp;\n  }\n}\n"],"names":["DefaultDynamicConfig","Promise","resolve","pkceRequiredForEmailMagicLinks","HeadlessB2BMagicLinksClient","email","authenticate","discovery","_config","dfpProtectedAuth","DisabledDFPProtectedAuthProvider","_networkClient","_subscriptionService","_pkceManager","_passwordResetPKCEManager","invite","data","fetchSDK","url","body","method","loginOrSignup","pkce_code_challenge","getCodeChallenge","requestBody","send","dfp_telemetry_id","captcha_token","getDFPTelemetryIDAndCaptcha","retriableFetchSDK","retryCallback","retryWithCaptchaAndDFP","withUpdateSession","passwordResetPKPair","getPKPair","resp","code_verifier","handlePKCEForAuthenticate","e","message","includes","console","log","pkPair","pkce_code_verifier","clearPKPair","undefined","keyPair","code_challenge","startPKCETransaction","pkceManager","intermediate_session_token","getIntermediateSessionToken"],"mappings":"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"}