Eiji Kitamura

Passkeys are designed to revolutionize the sign-in experience, offering a simpler, faster, and more secure alternative to passwords. This checklist will guide you through the key aspects of implementing passkeys to achieve optimal user experience (UX) outcomes.

How to use this checklist

This checklist is intended for developers and product teams implementing passkeys in their authentication flows. Use it to:

  • Validate that your implementation follows modern passkey UX best practices described in the following articles.
  • Identify required and optional elements that improve usability, security, and compatibility.
  • Check your implementation during development and before deployment.
  • Align with best practices that support user adoption and system interoperability.

These help you provide a smooth, secure experience for end users.

Passkeys registration

To make a smooth transition from passwords to passkeys on your website, having a sophisticated passkey registration capability is the key. Follow the instructions described in Create a passkey for passwordless logins to build a passkey registration feature on your website. Here are the things you should check in addition to the basic passkey registration features:

✅ Specify "platform" as the authenticator attachment value to pass to navigator.credentials.create() for a promoted passkey creation.

  • Provide optimized and frictionless passkey creation flow for those who are creating a passkey reactively.

✅ Verify the user with the strongest authentication method available for they can use before allowing them to create a passkey.

  • This is important to prevent an attacker from creating a passkey on a hijacked account.

✅ Prevent creating duplicate passkeys for the same passkey provider using excludeCredentials.

  • Many passkey providers accommodate only one passkey per an account and an RP ID. Avoid creating duplicates.

Use the AAGUID to identify the passkey provider and to name the credential for the user.

  • Associating a passkey with its passkey provider is an intuitive way to present a credential where it's possible.

✅ Signal if an attempt to register a passkey fails with PublicKeyCredential.signalUnknownCredential().

  • Stray passkeys can cause confusion. Let the passkey provider know if the server has failed to register a passkey.

Send a notification to the user after creating and registering a passkey for their account.

  • Make sure the user is aware of a passkey being created, especially when it's done by someone else.

Passkeys authentication

Accommodating both password users and passkey users without minimal friction can be a challenge. Follow the instructions described in Sign in with a passkey through form autofill to build a passkey form autofill feature on your website. Here are the things you should check in addition to the basic passkey authentication features:

✅ Allow users to sign in with a passkey through form autofill.

  • If your website is transitioning from passwords to passkeys, the best approach to accommodate both users is to use the browser's form autofill feature.

✅ Signal when a passkey's matching credential is not found on the backend with PublicKeyCredential.signalUnknownCredential().

  • Stray passkeys can cause confusion. Let the passkey provider know which passkey is not usable so the provider can delete it.

✅ Prompt users to manually create a passkey if the user hasn't created one after a sign-in.

  • If the user hasn't created a passkey yet, encourage them to create one.

Automatically create a passkey (conditional create) after the user signs in with a password (and a second factor).

  • Expedite user passkey adoption.

✅ Prompt for local passkey creation if the user has signed in with a cross-device passkey.

  • Creating a local passkey helps the user sign in without scanning a QR code from the next time.

Signal the list of available passkeys and updated user details (username, display name) to the provider after sign-in

  • Keeping the passkey list and user details in-sync between the server and the passkey provider improves the user experience.

Passkeys management

Giving a good grasp of passkeys for the users helps them get a better understanding of the landscape and control over the passkeys. Follow the instructions described in Help users manage passkeys effectively to build a passkey management feature on your website. Here are the things you should check:

✅ Allow users to manage passkeys in a passkey management page.

  • Create a central place where users can manage their passkeys.

✅ Support registering multiple passkeys.

  • An ability to register multiple passkeys helps users prevent themselves from a lock-out without falling back to a weaker authentication method.

✅ Allow users to add new and flexible types of passkeys on the management page.

✅ Display the passkey name.

  • Name passkeys based on the AAGUID and provide a tangible visual of the user's passkeys.

✅ Indicate whether a passkey is syncable or non-syncable.

  • Make the user aware when a passkey is not synced.

✅ Allow users to remove a public key from the server.

✅ Signal the list of passkeys when an associated public key is removed from the server.

  • Keeping the passkey list in-sync between the server and the passkey provider improves the user experience.
Example of a passkey management page showing good practices. Example of a passkey management page showing good practices.

Additional considerations

Signal the updated user details (username, display name) when the user updates it.

Create a passkey instead of a new password when a user "Forgot password".

Resources

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2022-06-05 UTC.

[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2022-06-05 UTC."],[],[]]