Skip to main content

Device-initiated authentication

Traditional passwordless sign-in methods such as email OTP are username-initiated. You enter your username (e.g. email address) and the site looks up the associated account and then initiates a challenge to verify it belongs to you.
But passkeys represent a new paradigm of device-initiated authentication. We can display passkeys available on a given device without requiring the user to enter a username.
Passkey credentials are either bound to a single device or synced between multiple devices by a password manager (Apple Passwords, Google Password Manager etc). The site can present whatever credentials are available on the device and we can look up the account based on the credential selected.

Availability across devices

Passkeys may not be available on a given device for multiple reasons.
  • If the user has created a passkey on one device then switched to a new device where that passkey can’t be synced.
  • If the user has created a passkey and then deleted it from their password manager.
For this reason your UI should always clearly present a backup authentication option and avoid leading users into dead ends when a passkey isn’t available.

Keeping credentials in sync

A related dead end occurs when a passkey is deleted on the server but still appears in the user’s password manager. The user selects it expecting it to work, but the server no longer recognizes it. The Web SDK reduces this by using the WebAuthn Signal API to prune stale credentials from the browser after each sign-up and sign-in. This is enabled by default via the syncCredentials option, so in supporting browsers the user’s passkey list stays aligned with the credentials Authsignal holds without any extra work on your part.

Passkeys for sign-in

Autofill

Enabling passkey autofill is an unobtrusive way to support passkeys on your sign-in page while also maintaining a familiar experience for users who haven’t setup passkeys yet.
Here the user will only be shown a passkey if they have already created one and it’s available on the device. Otherwise the user can manually enter their username and press “Continue” to trigger another kind of challenge (e.g. email OTP).

Sign-in button

Another approach is to include a separate passkey sign-in button which is clearly presented as an alternative sign-in option.
Clicking this button will launch the browser passkey prompt regardless of whether or not there are any passkeys available on the device. If a passkey is available, then the user will be able to authenticate with it.
If no passkey is available, however, then the browser has to fall back to displaying a QR code or waiting for the user to insert a hardware security key.
This QR code prompt can be useful if the user knows what to do; for example, if they’ve previously created a passkey on their iPhone and are now on their Windows laptop, then they can scan the QR code with their iPhone in order to sign in. However, the QR code prompt can be a jarring or confusing experience to users who aren’t familiar with the nuances of how passkeys are synced across different platforms. For this reason we strongly recommend restricting the QR code flow to a passkey sign-in button or a similar UI interaction where the user has explicitly chosen to use passkeys.

Immediate mediation

To avoid the QR code fallback entirely, you can use immediate mediation. The browser only shows the passkey prompt when a credential is immediately available on the device; if none is available, the prompt is skipped rather than falling back to a QR code, so the user is never led into the dead end described above. This makes immediate mediation well suited to surfacing a passkey prompt automatically on page load, without risking a confusing experience for users who don’t have a passkey on the device. To enable it, set preferImmediatelyAvailableCredentials to true when calling signIn. See the Web SDK reference for details.
Immediate mediation depends on newer browser APIs and at the time of writing is only supported in recent versions of Chromium-based browsers. The SDK feature-detects support and returns an immediate_mediation_not_supported error code where it isn’t available, so always keep a backup authentication option for users on unsupported browsers or without an available passkey.

Passkeys for MFA

When using passkeys as a secondary factor, it’s important to only show passkeys for one account. If a device is shared between family members, or if a person has multiple accounts for the same site, then a device may have passkeys available for different accounts.
The allowCredentials parameter is the solution here; it lets us tell the browser to restrict passkeys to a known list of credentials for a given user. But even if you know all passkeys a user has previously created, you still can’t guarantee any will be available on the device the user is currently authenticating on. If you pass the browser a list of allowed credentials but it doesn’t find any on that device, then it will fall back to presenting a QR code. So even when using allowCredentials it’s important to clearly present a backup authentication option and avoid leading users into dead ends when their device doesn’t have any passkeys available.
Because it is always launched for a specific user, the Authsignal pre-built UI always restricts passkeys via the allowCredentials parameter. It also provides a clear way to fall back to alternate authentication methods.

Security keys for high-assurance flows

Most consumer flows should default to platform passkeys (the device’s built-in authenticator), which give the smoothest experience. For workforce or high-assurance scenarios that require a physical hardware authenticator, you can use security keys instead. To steer the browser towards a specific authenticator type, pass the hints parameter (for example ["security-key"]) when creating a passkey or security key. When you support both platform authenticators and security keys, present them as distinct options (for example “This device” versus “USB security key”) so the choice is predictable.
Hints are advisory, not a security guarantee. They are ignored on some platforms (such as Windows Hello), so always validate the authenticator type on your server if you need to enforce it.

Creating passkeys

Increasing adoption

Transitioning your users from traditional sign in methods, like passwords, to passkeys can be a big change. To help with this transition, you can provide a prompt to encourage users to create a passkey when they sign in.
As this may be the first time your users have encountered passkeys, it’s important to provide a summary of what passkeys are and their benefits. Choose the right moment. Usability research from the FIDO Alliance shows that the highest-converting moments to offer passkey creation are during account creation, in account settings, and immediately after account recovery. Prompting in the middle of the sign-in flow itself tends to convert less well, so prefer these account-management moments and always provide a clear “not now” option along with a path to create a passkey later from settings. Respect a user’s dismissal and avoid re-prompting a user who has already enrolled a passkey.

Automatic passkey upgrades

You can remove the passkey creation prompt entirely for users who already rely on a password manager. After a successful password sign-in, the SDK can ask the user’s password manager to silently create a passkey in the background, with no extra step for the user. To enable this, set useAutoRegister to true when calling signUp. See Automatic passkey upgrades in the Web SDK reference for details.
Automatic upgrades only work when the user has a saved password for your app and their browser and password manager support conditional create. The SDK feature-detects support, and the flow fails silently when conditions aren’t met, so it’s safe to attempt without disrupting the user.

Improving coverage across devices

Whilst many passkeys are available across devices, like ones stored in iCloud Keychain, some passkeys are device-bound. For example, a passkey created on a desktop browser may not be available on a mobile device. If a user authenticates on a device without a passkey, you can prompt them to create one in a similar way to the example above.
This is especially valuable right after a cross-device (QR code) sign-in. Because that flow used a passkey on another device, the current device still has none. Offering to create a local passkey at that moment turns a one-off QR scan into a faster sign-in next time. Depending on your needs, you can alter the frequency of these prompts to ensure they’re not too intrusive. This could be a timed cooldown or based on the user’s behaviour.

Handling cancellations and errors

When a passkey ceremony fails, the SDK throws a WebAuthnError. Most of these are a normal part of the user experience and should not surface a disruptive error. The most common case is ERROR_CEREMONY_ABORTED, thrown when the user dismisses the passkey prompt. The underlying browser API deliberately does not distinguish “the user cancelled” from “no passkey was available”, so treat this as an expected outcome: quietly fall back to your backup authentication method rather than showing an error. This ambiguity is the main reason to prefer autofill and immediate mediation where possible, since both surface passkeys only when one is actually available and avoid the dead end entirely. See Passkey error handling in the Web SDK reference for the full list of error codes.

Displaying passkeys

As users may have multiple passkeys, it’s useful to display them in a distinct way. A passkey user authenticator contains the webauthnCredential.aaguidMapping object. The name field will contain the name of the credential manager, e.g. iCloud Keychain, where the passkey is stored. The svgDark/svgLight fields contain the SVG icons for the credential manager. In the area of your application where user’s manage their authentication options, you can utilize these fields to display the user’s passkeys:
Alongside the provider name and icon, showing the created and last used dates (available on the user authenticator) helps users recognise each passkey and gives them the confidence to remove the right one. Encourage users to keep more than one passkey so deleting a single credential never locks them out.
Whilst the webauthnCredential.aaguidMapping object is available for most passkeys, it’s not guaranteed to be present. As an alternative, you can use the webauthnCredential.parsedUserAgent object to display details about the device the passkey was created on.