WebAuthn authentication functionality for logging in users with previously registered authenticators, including support for conditional UI (browser autofill) and multi-device authentication scenarios.
Begin authenticator login via WebAuthn assertion ceremony.
/**
* Begin authenticator "login" via WebAuthn assertion
* @param options Configuration object containing authentication options and settings
* @returns Promise resolving to authentication response suitable for server verification
*/
function startAuthentication(options: {
optionsJSON: PublicKeyCredentialRequestOptionsJSON;
useBrowserAutofill?: boolean;
verifyBrowserAutofillInput?: boolean;
}): Promise<AuthenticationResponseJSON>;
type StartAuthenticationOpts = Parameters<typeof startAuthentication>[0];Parameters:
optionsJSON: Authentication options from your server's generateAuthenticationOptions() calluseBrowserAutofill: Optional boolean to initialize conditional UI for logging in via browser autofill prompts (defaults to false)verifyBrowserAutofillInput: Optional boolean to ensure a suitable <input> element is present when useBrowserAutofill is true (defaults to true)Usage Examples:
import { startAuthentication } from "@simplewebauthn/browser";
// Basic authentication
const authenticationOptions = await fetch("/webauthn/authenticate/begin").then(r => r.json());
try {
const authenticationResponse = await startAuthentication({
optionsJSON: authenticationOptions,
});
console.log("Authentication successful:", authenticationResponse);
// Send to server for verification
const verificationResponse = await fetch("/webauthn/authenticate/finish", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(authenticationResponse),
});
} catch (error) {
console.error("Authentication failed:", error);
}
// Authentication with browser autofill (conditional UI)
// First ensure you have an input with webauthn autocomplete
// <input type="text" autocomplete="username webauthn" />
try {
const authenticationResponse = await startAuthentication({
optionsJSON: authenticationOptions,
useBrowserAutofill: true, // Enable autofill UI
});
} catch (error) {
if (error.message.includes("No <input> with")) {
console.log("Missing required input element for autofill");
}
}
// Skip input validation for autofill (advanced usage)
try {
const authenticationResponse = await startAuthentication({
optionsJSON: authenticationOptions,
useBrowserAutofill: true,
verifyBrowserAutofillInput: false, // Skip input validation
});
} catch (error) {
console.error("Authentication failed:", error);
}The raw credential returned from navigator.credentials.get().
interface AuthenticationCredential extends PublicKeyCredentialFuture {
response: AuthenticatorAssertionResponse;
}
interface PublicKeyCredentialFuture extends PublicKeyCredential {
type: PublicKeyCredentialType;
isConditionalMediationAvailable?(): Promise<boolean>;
parseCreationOptionsFromJSON?(
options: PublicKeyCredentialCreationOptionsJSON,
): PublicKeyCredentialCreationOptions;
parseRequestOptionsFromJSON?(
options: PublicKeyCredentialRequestOptionsJSON,
): PublicKeyCredentialRequestOptions;
toJSON?(): PublicKeyCredentialJSON;
}JSON-serializable authentication response with Base64URL-encoded ArrayBuffers.
/**
* A slightly-modified AuthenticationCredential to simplify working with ArrayBuffers that
* are Base64URL-encoded in the browser so that they can be sent as JSON to the server.
*/
interface AuthenticationResponseJSON {
id: Base64URLString;
rawId: Base64URLString;
response: AuthenticatorAssertionResponseJSON;
authenticatorAttachment?: AuthenticatorAttachment;
clientExtensionResults: AuthenticationExtensionsClientOutputs;
type: PublicKeyCredentialType;
}
interface AuthenticatorAssertionResponseJSON {
clientDataJSON: Base64URLString;
authenticatorData: Base64URLString;
signature: Base64URLString;
userHandle?: Base64URLString;
}Options for WebAuthn authentication ceremony.
/**
* A variant of PublicKeyCredentialRequestOptions suitable for JSON transmission to the browser to
* (eventually) get passed into navigator.credentials.get(...) in the browser.
*/
interface PublicKeyCredentialRequestOptionsJSON {
challenge: Base64URLString;
timeout?: number;
rpId?: string;
allowCredentials?: PublicKeyCredentialDescriptorJSON[];
userVerification?: UserVerificationRequirement;
hints?: PublicKeyCredentialHint[];
extensions?: AuthenticationExtensionsClientInputs;
}
interface PublicKeyCredentialDescriptorJSON {
id: Base64URLString;
type: PublicKeyCredentialType;
transports?: AuthenticatorTransportFuture[];
}For conditional UI (autofill) authentication, you need a properly configured input element:
<!-- Required for browser autofill -->
<input type="text" autocomplete="username webauthn" />
<!-- Also works with -->
<input type="email" autocomplete="email webauthn" />The input must have webauthn as the last or only value in its autocomplete attribute. The library will automatically detect and validate this requirement unless verifyBrowserAutofillInput is set to false.
Autofill Requirements:
browserSupportsWebAuthnAutofill())webauthn in its autocomplete attributeallowCredentials in options will be automatically cleared for conditional UIimport {
startAuthentication,
browserSupportsWebAuthnAutofill
} from "@simplewebauthn/browser";
// Check support first
if (await browserSupportsWebAuthnAutofill()) {
const response = await startAuthentication({
optionsJSON: authOptions,
useBrowserAutofill: true,
});
}Authentication can throw various WebAuthn-specific errors. Common error scenarios:
browserSupportsWebAuthn() firstimport { startAuthentication, WebAuthnError } from "@simplewebauthn/browser";
try {
const response = await startAuthentication({ optionsJSON });
} catch (error) {
if (error instanceof WebAuthnError) {
switch (error.code) {
case 'ERROR_CEREMONY_ABORTED':
console.log("User cancelled authentication");
break;
case 'ERROR_INVALID_DOMAIN':
console.log("Invalid domain for WebAuthn");
break;
default:
console.log(`Authentication error: ${error.code}`);
}
} else if (error.message.includes("Browser does not support WebAuthn autofill")) {
console.log("Autofill not supported, use regular authentication");
} else if (error.message.includes("No <input> with")) {
console.log("Missing required input for autofill");
}
}