diff options
author | Matthew Miller <matthew@millerti.me> | 2022-07-04 08:04:44 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-04 08:04:44 -0700 |
commit | 184cbb4457285817db4ded722d7b54528988e2e0 (patch) | |
tree | 3b895f8c273e924dd6fdd52c50fd2528575dc41d /packages/browser/src/methods/startAuthentication.ts | |
parent | 524e7f881624f36aa17f406bb25fa23d02449652 (diff) | |
parent | 5a5b5a3bdf7c709493fc9e63f0f02eed99f25baf (diff) |
Merge pull request #214 from MasterKale/feat/conditional-ui
feat/conditional-ui
Diffstat (limited to 'packages/browser/src/methods/startAuthentication.ts')
-rw-r--r-- | packages/browser/src/methods/startAuthentication.ts | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/packages/browser/src/methods/startAuthentication.ts b/packages/browser/src/methods/startAuthentication.ts index ee401a1..7887228 100644 --- a/packages/browser/src/methods/startAuthentication.ts +++ b/packages/browser/src/methods/startAuthentication.ts @@ -8,16 +8,21 @@ import bufferToBase64URLString from '../helpers/bufferToBase64URLString'; import base64URLStringToBuffer from '../helpers/base64URLStringToBuffer'; import bufferToUTF8String from '../helpers/bufferToUTF8String'; import { browserSupportsWebauthn } from '../helpers/browserSupportsWebauthn'; +import { browserSupportsWebAuthnAutofill } from '../helpers/browserSupportsWebAuthnAutofill'; import toPublicKeyCredentialDescriptor from '../helpers/toPublicKeyCredentialDescriptor'; import { identifyAuthenticationError } from '../helpers/identifyAuthenticationError'; +import { webauthnAbortService } from '../helpers/webAuthnAbortService'; /** * Begin authenticator "login" via WebAuthn assertion * - * @param requestOptionsJSON Output from @simplewebauthn/server's generateAssertionOptions(...) + * @param requestOptionsJSON Output from **@simplewebauthn/server**'s generateAssertionOptions(...) + * @param useBrowserAutofill Initialize conditional UI to enable logging in via browser + * autofill prompts */ -export default async function startAuthentication( +export async function startAuthentication( requestOptionsJSON: PublicKeyCredentialRequestOptionsJSON, + useBrowserAutofill = false, ): Promise<AuthenticationCredentialJSON> { if (!browserSupportsWebauthn()) { throw new Error('WebAuthn is not supported in this browser'); @@ -37,7 +42,37 @@ export default async function startAuthentication( allowCredentials, }; - const options: CredentialRequestOptions = { publicKey }; + // Prepare options for `.get()` + const options: CredentialRequestOptions = {}; + + /** + * Set up the page to prompt the user to select a credential for authentication via the browser's + * input autofill mechanism. + */ + if (useBrowserAutofill) { + 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; + // Conditional UI requires an empty allow list + publicKey.allowCredentials = []; + } + + // Finalize options + options.publicKey = publicKey; + // Set up the ability to cancel this request if the user attempts another + options.signal = webauthnAbortService.createNewAbortSignal(); // Wait for the user to complete assertion let credential; @@ -45,6 +80,8 @@ export default async function startAuthentication( credential = (await navigator.credentials.get(options)) as AuthenticationCredential; } catch (err) { throw identifyAuthenticationError({ error: err as Error, options }); + } finally { + webauthnAbortService.reset(); } if (!credential) { |