diff options
-rw-r--r-- | packages/browser/src/helpers/browserSupportsConditionalMediation.ts | 15 | ||||
-rw-r--r-- | packages/browser/src/methods/startAuthentication.ts | 25 |
2 files changed, 40 insertions, 0 deletions
diff --git a/packages/browser/src/helpers/browserSupportsConditionalMediation.ts b/packages/browser/src/helpers/browserSupportsConditionalMediation.ts new file mode 100644 index 0000000..e3fbcea --- /dev/null +++ b/packages/browser/src/helpers/browserSupportsConditionalMediation.ts @@ -0,0 +1,15 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +export async function browserSupportsWebAuthnAutofill(): Promise<boolean> { + // Just for Chrome Canary right now; the PublicKeyCredential logic below is the real API + // @ts-ignore + if (navigator.credentials.conditionalMediationSupported) { + return true; + } + + return ( + // @ts-ignore + PublicKeyCredential.isConditionalMediationAvailable + // @ts-ignore + && PublicKeyCredential.isConditionalMediationAvailable() + ); +} diff --git a/packages/browser/src/methods/startAuthentication.ts b/packages/browser/src/methods/startAuthentication.ts index a08e3a3..a12c8fd 100644 --- a/packages/browser/src/methods/startAuthentication.ts +++ b/packages/browser/src/methods/startAuthentication.ts @@ -8,6 +8,7 @@ import bufferToBase64URLString from '../helpers/bufferToBase64URLString'; import base64URLStringToBuffer from '../helpers/base64URLStringToBuffer'; import bufferToUTF8String from '../helpers/bufferToUTF8String'; import { browserSupportsWebauthn } from '../helpers/browserSupportsWebauthn'; +import { browserSupportsWebAuthnAutofill } from '../helpers/browserSupportsConditionalMediation'; import toPublicKeyCredentialDescriptor from '../helpers/toPublicKeyCredentialDescriptor'; import { identifyAuthenticationError } from '../helpers/identifyAuthenticationError'; @@ -42,6 +43,30 @@ export default async function startAuthentication( const options: CredentialRequestOptions = { publicKey }; + /** + * Set up the page to prompt the user to select a credential for authentication via the browser's + * input autofill mechanism. + */ + if (supportBrowserAutofill) { + if (!(await browserSupportsWebAuthnAutofill())) { + throw Error('Browser does not support WebAuthn autofill'); + } + + // Check for an <input> with "webauthn" in its `autocomplete` attribute + const eligibleInputs = document.querySelectorAll("input[autocomplete*='webauthn']"); + + // WebAuthn autofill requires at least one valid input + if (eligibleInputs.length < 1) { + throw Error('No <input> with `"webauthn"` in its `autocomplete` attribute was detected'); + } + + // `CredentialMediationRequirement` doesn't know about "conditional" yet as of + // typescript@4.6.3 + options.mediation = 'conditional' as CredentialMediationRequirement; + // Massage options into a suitable structure + delete options.publicKey?.allowCredentials; + } + // Wait for the user to complete assertion let credential; try { |