{"version":3,"file":"HeadlessWebAuthnClient.mjs","sources":["../../../../../../../core/src/HeadlessClients/HeadlessWebAuthnClient.ts"],"sourcesContent":["import * as webauthnJson from '@github/webauthn-json';\n\nimport { IConsumerSubscriptionService, IDFPProtectedAuthProvider, INetworkClient } from '..';\nimport {\n  IHeadlessWebAuthnClient,\n  StytchProjectConfigurationInput,\n  WebAuthnAuthenticateResponse,\n  WebAuthnAuthenticateStartOptions,\n  WebAuthnAuthenticateStartResponse,\n  WebAuthnRegisterResponse,\n  WebAuthnRegisterStartOptions,\n  WebAuthnRegisterStartResponse,\n  WebAuthnUpdateOptions,\n  WebAuthnUpdateResponse,\n} from '../public';\nimport { logger, omitUser, WithUser } from '../utils';\nimport { validateInDev } from '../utils/dev';\n\nexport class HeadlessWebAuthnClient<TProjectConfiguration extends StytchProjectConfigurationInput>\n  implements IHeadlessWebAuthnClient<TProjectConfiguration>\n{\n  register: (options: WebAuthnRegisterStartOptions) => Promise<WebAuthnRegisterResponse<TProjectConfiguration>>;\n\n  authenticate: (\n    options: WebAuthnAuthenticateStartOptions,\n  ) => Promise<WebAuthnAuthenticateResponse<TProjectConfiguration> | null>;\n\n  constructor(\n    public _networkClient: INetworkClient,\n    private _subscriptionService: IConsumerSubscriptionService<TProjectConfiguration>,\n    private dfpProtectedAuth: IDFPProtectedAuthProvider,\n  ) {\n    this.register = this._subscriptionService.withUpdateSession(\n      async (options?: WebAuthnRegisterStartOptions): Promise<WebAuthnRegisterResponse<TProjectConfiguration>> => {\n        if (options) {\n          validateInDev('stytch.webauthn.register', options, {\n            domain: 'optionalString',\n            authenticator_type: 'optionalString',\n            is_passkey: 'optionalBoolean',\n            session_duration_minutes: 'number',\n            override_id: 'optionalString',\n            override_name: 'optionalString',\n            override_display_name: 'optionalString',\n            use_base64_url_encoding: 'optionalBoolean',\n          });\n        }\n\n        const startResp = await this._networkClient.fetchSDK<WebAuthnRegisterStartResponse>({\n          url: '/webauthn/register/start',\n          method: 'POST',\n          body: {\n            domain: options?.domain ?? window.location.hostname,\n            authenticator_type: options?.authenticator_type ?? undefined,\n            return_passkey_credential_options: options?.is_passkey,\n            override_id: options?.override_id,\n            override_name: options?.override_name,\n            override_display_name: options?.override_display_name,\n            user_agent: navigator.userAgent,\n            use_base64_url_encoding: options?.use_base64_url_encoding,\n          },\n        });\n\n        const publicKeyCredentialCreationOptions = startResp.public_key_credential_creation_options;\n        const publicKey = JSON.parse(publicKeyCredentialCreationOptions);\n\n        const credential = await webauthnJson.create({\n          publicKey: publicKey,\n        });\n\n        const resp = await this._networkClient.fetchSDK<WithUser<WebAuthnRegisterResponse<TProjectConfiguration>>>({\n          url: '/webauthn/register',\n          method: 'POST',\n          body: {\n            public_key_credential: JSON.stringify(credential),\n            session_duration_minutes: options?.session_duration_minutes,\n          },\n        });\n\n        return omitUser(resp);\n      },\n    );\n\n    this.authenticate = this._subscriptionService.withUpdateSession(\n      async (\n        options: WebAuthnAuthenticateStartOptions,\n      ): Promise<WebAuthnAuthenticateResponse<TProjectConfiguration> | null> => {\n        validateInDev('stytch.webauthn.authenticate', options, {\n          domain: 'optionalString',\n          session_duration_minutes: 'number',\n          is_passkey: 'optionalBoolean',\n          signal: 'optionalObject',\n          conditional_mediation: 'optionalBoolean',\n          disable_input_check: 'optionalBoolean',\n        });\n        const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();\n\n        if (options.conditional_mediation) {\n          if (!(await this.browserSupportsAutofill())) {\n            logger.error('Browser does not support WebAuthn autofill');\n            return null;\n          }\n\n          if (!options.disable_input_check && !this.checkEligibleInputs()) {\n            return null;\n          }\n        }\n\n        const isLoggedIn = !!this._subscriptionService.getSession();\n\n        const endpoint = isLoggedIn ? '/webauthn/authenticate/start/secondary' : '/webauthn/authenticate/start/primary';\n\n        const startResp = await this._networkClient.fetchSDK<WebAuthnAuthenticateStartResponse>({\n          url: endpoint,\n          method: 'POST',\n          body: {\n            domain: options.domain ?? window.location.hostname,\n            return_passkey_credential_options: options?.is_passkey,\n          },\n        });\n\n        const publicKeyCredentialRequestOptions = startResp.public_key_credential_request_options;\n        const abortController = new AbortController();\n        const credReqOptions = {\n          publicKey: JSON.parse(publicKeyCredentialRequestOptions),\n          signal: options.signal ?? abortController.signal,\n        };\n        const conditionalMediationCredReqOption = {\n          ...credReqOptions,\n          mediation: 'conditional' as CredentialMediationRequirement,\n        };\n        const credential = await webauthnJson.get(\n          options.conditional_mediation ? conditionalMediationCredReqOption : credReqOptions,\n        );\n\n        const authenticationData = await this._networkClient.retriableFetchSDK<\n          WithUser<WebAuthnAuthenticateResponse<TProjectConfiguration>>\n        >({\n          url: '/webauthn/authenticate',\n          method: 'POST',\n          body: {\n            public_key_credential: JSON.stringify(credential),\n            session_duration_minutes: options.session_duration_minutes,\n            dfp_telemetry_id,\n            captcha_token,\n          },\n          retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP,\n        });\n\n        return omitUser(authenticationData);\n      },\n    );\n  }\n\n  async update(options: WebAuthnUpdateOptions): Promise<WebAuthnUpdateResponse> {\n    validateInDev('stytch.webauthn.update', options, {\n      webauthn_registration_id: 'string',\n      name: 'string',\n    });\n\n    const url = '/webauthn/update/' + options.webauthn_registration_id;\n    return await this._networkClient.fetchSDK<WebAuthnUpdateResponse>({\n      url: url,\n      method: 'PUT',\n      body: {\n        name: options.name,\n      },\n    });\n  }\n\n  async browserSupportsAutofill(): Promise<boolean> {\n    return (await window.PublicKeyCredential?.isConditionalMediationAvailable?.()) ?? false;\n  }\n\n  private checkEligibleInputs = (): boolean => {\n    // Check for an <input> with \"webauthn\" in its `autocomplete` attribute\n    const eligibleInputs = document.querySelectorAll(\"input[autocomplete*='webauthn']\");\n    // WebAuthn autofill requires at least one valid input\n    if (eligibleInputs.length < 1) {\n      logger.error('No <input> with `\"webauthn\"` in its `autocomplete` attribute was detected');\n      return false;\n    }\n    return true;\n  };\n}\n"],"names":["HeadlessWebAuthnClient","register","authenticate","_networkClient","_subscriptionService","dfpProtectedAuth","withUpdateSession","options","validateInDev","domain","authenticator_type","is_passkey","session_duration_minutes","override_id","override_name","override_display_name","use_base64_url_encoding","startResp","fetchSDK","url","method","body","window","location","hostname","undefined","return_passkey_credential_options","user_agent","navigator","userAgent","publicKeyCredentialCreationOptions","public_key_credential_creation_options","publicKey","JSON","parse","credential","webauthnJson","resp","public_key_credential","stringify","omitUser","signal","conditional_mediation","disable_input_check","dfp_telemetry_id","captcha_token","getDFPTelemetryIDAndCaptcha","browserSupportsAutofill","logger","error","checkEligibleInputs","isLoggedIn","getSession","endpoint","publicKeyCredentialRequestOptions","public_key_credential_request_options","abortController","AbortController","credReqOptions","conditionalMediationCredReqOption","mediation","authenticationData","retriableFetchSDK","retryCallback","retryWithCaptchaAndDFP","update","webauthn_registration_id","name","PublicKeyCredential","isConditionalMediationAvailable","eligibleInputs","document","querySelectorAll","length"],"mappings":"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"}