{"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","validateInDev","email_address","invite_redirect_url","invite_template_id","name","locale","roles","invite_expiration_minutes","fetchSDK","url","body","method","loginOrSignup","organization_id","login_redirect_url","login_template_id","signup_redirect_url","signup_template_id","login_expiration_minutes","signup_expiration_minutes","pkce_code_challenge","getCodeChallenge","requestBody","send","discovery_redirect_url","discovery_expiration_minutes","dfp_telemetry_id","captcha_token","getDFPTelemetryIDAndCaptcha","retriableFetchSDK","retryCallback","retryWithCaptchaAndDFP","withUpdateSession","magic_links_token","session_duration_minutes","passwordResetPKPair","getPKPair","resp","code_verifier","handlePKCEForAuthenticate","e","message","includes","console","log","discovery_magic_links_token","pkPair","pkce_code_verifier","clearPKPair","undefined","keyPair","code_challenge","startPKCETransaction","pkceManager","intermediate_session_token","getIntermediateSessionToken"],"mappings":"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"}