@@ -48,6 +48,12 @@ type WebAuthnMetadata = WebAuthnAuthenticationMetadata | WebAuthnRegistrationMet
4848type WebAuthnTextOutput = WebAuthnTextOutputRegistration ;
4949const TWO_SECOND = 2000 ;
5050
51+ declare global {
52+ interface Window {
53+ PingWebAuthnAbortController : AbortController ;
54+ }
55+ }
56+
5157/**
5258 * Utility for integrating a web browser's WebAuthn API.
5359 *
@@ -151,27 +157,30 @@ abstract class FRWebAuthn {
151157
152158 try {
153159 let publicKey : PublicKeyCredentialRequestOptions ;
154- let useConditionalUI = false ;
155160
156161 if ( metadataCallback ) {
157162 const meta = metadataCallback . getOutputValue ( 'data' ) as WebAuthnAuthenticationMetadata ;
163+ const mediation = meta . mediation as CredentialMediationRequirement ;
164+
165+ if ( mediation === 'conditional' ) {
166+ const isConditionalSupported = await this . isConditionalUISupported ( ) ;
167+ if ( ! isConditionalSupported ) {
168+ const e = new Error (
169+ 'Conditional UI was requested, but is not supported by this browser.' ,
170+ ) ;
171+ e . name = WebAuthnOutcomeType . NotSupportedError ;
172+ throw e ;
173+ }
174+ }
158175
159- // Check if server indicates conditional UI should be used
160- useConditionalUI = meta . conditional === 'true' ;
161176 publicKey = this . createAuthenticationPublicKey ( meta ) ;
162177
163- credential = await this . getAuthenticationCredential (
164- publicKey as PublicKeyCredentialRequestOptions ,
165- useConditionalUI ,
166- ) ;
178+ credential = await this . getAuthenticationCredential ( { publicKey, mediation } ) ;
167179 outcome = this . getAuthenticationOutcome ( credential ) ;
168180 } else if ( textOutputCallback ) {
169181 publicKey = parseWebAuthnAuthenticateText ( textOutputCallback . getMessage ( ) ) ;
170182
171- credential = await this . getAuthenticationCredential (
172- publicKey as PublicKeyCredentialRequestOptions ,
173- false , // Script-based callbacks don't support conditional UI
174- ) ;
183+ credential = await this . getAuthenticationCredential ( { publicKey } ) ;
175184 outcome = this . getAuthenticationOutcome ( credential ) ;
176185 } else {
177186 throw new Error ( 'No Credential found from Public Key' ) ;
@@ -349,37 +358,23 @@ abstract class FRWebAuthn {
349358 /**
350359 * Retrieves the credential from the browser Web Authentication API.
351360 *
352- * @param options The public key options associated with the request
353- * @param useConditionalUI Whether to use conditional UI (autofill)
361+ * @param options The options associated with the request
354362 * @return The credential
355363 */
356364 public static async getAuthenticationCredential (
357- options : PublicKeyCredentialRequestOptions ,
358- useConditionalUI = false ,
365+ options : CredentialRequestOptions ,
359366 ) : Promise < PublicKeyCredential | null > {
360367 // Feature check before we attempt authenticating
361368 if ( ! window . PublicKeyCredential ) {
362369 const e = new Error ( 'PublicKeyCredential not supported by this browser' ) ;
363370 e . name = WebAuthnOutcomeType . NotSupportedError ;
364371 throw e ;
365372 }
366- // Build the credential request options
367- const credentialRequestOptions : CredentialRequestOptions = {
368- publicKey : options ,
369- } ;
370373
371- // Add conditional mediation if requested and supported
372- if ( useConditionalUI ) {
373- const isConditionalSupported = await this . isConditionalUISupported ( ) ;
374- if ( isConditionalSupported ) {
375- credentialRequestOptions . mediation = 'conditional' as CredentialMediationRequirement ;
376- } else {
377- // eslint-disable-next-line no-console
378- FRLogger . warn ( 'Conditional UI was requested, but is not supported by this browser.' ) ;
379- }
380- }
381-
382- const credential = await navigator . credentials . get ( credentialRequestOptions ) ;
374+ const credential = await navigator . credentials . get ( {
375+ ...options ,
376+ signal : this . createAbortController ( ) . signal ,
377+ } ) ;
383378 return credential as PublicKeyCredential ;
384379 }
385380
@@ -599,6 +594,14 @@ abstract class FRWebAuthn {
599594 } ,
600595 } ;
601596 }
597+
598+ private static createAbortController ( ) {
599+ window . PingWebAuthnAbortController ?. abort ( ) ;
600+
601+ const abortController = new AbortController ( ) ;
602+ window . PingWebAuthnAbortController = abortController ;
603+ return abortController ;
604+ }
602605}
603606
604607export default FRWebAuthn ;
@@ -608,4 +611,4 @@ export type {
608611 WebAuthnCallbacks ,
609612 WebAuthnRegistrationMetadata ,
610613} ;
611- export { WebAuthnOutcome , WebAuthnStepType } ;
614+ export { WebAuthnOutcome , WebAuthnOutcomeType , WebAuthnStepType } ;
0 commit comments