DEV Community

Cover image for The Road to Passkey Adoption: A Developer’s Perspective
Nicholas DeWald for Prove Identity

Posted on • Originally published at prove.com

The Road to Passkey Adoption: A Developer’s Perspective

This article focuses on some technical aspects of implementing a passkey authentication mechanism. In the previous article, we focused on what passkey authentication is, and in the next article, we’ll dive into details related to the user experience and business decisions.

‍Passkeys are a new authentication mechanism intended to replace passwords, utilizing public key infrastructure to address a majority of the security challenges we face with passwords. Public key infrastructure provides two things: first, authentication – it can prove who sends a message; second, authorization – it ensures that no one other than the intended recipient can read a message. FIDO2 passkeys utilize these characteristics to provide more secure authentication.

‍Passkeys are specified by the FIDO Alliance and include both software and hardware standards. FIDO2 specifically focuses on the use of passkeys in a web application, which requires the ability of the hosting web browser to interact with the underlying platform to securely create and store private keys. The FIDO2 part of the specification focuses on the interaction between a web application and a FIDO server, and WebAuthN focuses on the interaction of the web application with the browser, as well as the underlying platform.

‍Since FIDO2 and WebAuthN are open standards, it’s possible to read the standards yourself (WebAuthN, FIDO) and add passwordless functionality to your web application. However, while the specification is open, there is a complexity to understanding the details, building and maintaining the server, and keeping up to date with the changes (this is a cutting-edge technology that’s moving fast) while making it easy to integrate into your existing infrastructure. This article provides an overview, distilling the core functionality.

‍We begin by iterating on the interaction/flow required for passwordless authentication. There are two flows, one for registration (creating credentials) and one for authentication.

Reviewing Flows

Traditional password flows rely on a “shared secret.” In contrast, passkeys rely on Public Key Infrastructure, where the client stores the private key and the server stores the public key. The client creates both keys, only sending the public key to the server. Understanding how the registration and authentication processes work is necessary before any passkey implementation can be done.

‍We can implement passkeys in web applications as long as they are running in a FIDO2-compliant browser, with appropriate FIDO2 Authenticators attached. In the following discussion, we’ve represented the FIDO2 functionality used by a web application in a FIDO2 JS SDK library. We also need a web server that can store public keys (key storage) and handle cryptographic tasks.

‍With traditional password authentication, a web application could run in a browser and talk with a server, and the browser doesn’t really matter too much. Since passkeys are created and stored on the underlying platform (that is, either the mobile device or laptop the browser is running on), the browser needs to communicate with the platform and authenticators. Luckily, these days most (>97%, accessed Dec 2023) browsers are FIDO2 compliant (examples here, including Chrome, Edge, Safari, and Firefox), but not all platforms have authenticators built in. Authenticators are the components that run the cryptographic operations to generate, store, and evaluate key pairs. This usually includes some kind of secure hardware storage. Most mobile phones with modern, updated browsers fit this requirement. And, if we can create passkeys on a mobile device, we can use them to authenticate on a device (such as a laptop) that doesn’t meet these requirements.

‍Now, let’s see how these things work together to enable passkey.

Registration

The registration flow is what happens when someone creates a new account, or if someone wants to create a new passkey (it’s a good idea for users to have more than one passkey for each account). The process is depicted in the diagram below:

Image description

Let’s review what we see above:‍

  • Steps 1–3: The user will enter the desired username in a form, and clicking “Register” will invoke the start of the credential creation flow. The application asks the server to register a username.

  • Step 4: The server generates some information about what is allowed to be used as an authenticator. This includes things like what cryptographic algorithms to use and the hardware capabilities or security mechanisms on the authenticator. This is sent back to the client.

  • Steps 5–7: This is where we invoke the WebAuthN mechanism to ask for new credentials to be created. The options specified by the server are passed through the browser (Step 6) to the underlying platform and any appropriate authenticators that are available (Step 7). “Appropriate authenticators” means any authenticator that matches the options specified by the server earlier.

  • Steps 8–9: Most use cases will ask authenticators to protect the credentials with a biometric interaction. When that’s the case, the user will be asked to perform the biometric interaction, then will generate the public and private keys to be used in subsequent authentication actions.

  • Steps 10–12: After the keys are created, the public key is packaged up with some other information, such as details about the authenticator that was used to create the credentials. This information is passed back to the server.

  • Step 13: The server will review the details about the authenticator. In particular, this is where the server ensures that the authenticator has not been reported as insecure or compromised.

  • Step 14: The server stores the public key data and any other metadata.

  • Step 15–end: Assuming success, return to the web application that credentials are created in and the user can continue.

    Once the registration is completed, the user can return and authenticate later.

Authentication

Once a passkey has been created, it can be used for authentication. The general approach is as follows:

Image description

  • Steps 1–2: The client tells the server it wants to authenticate a given username.

  • Step 3-4: The server looks up the public key associated with the specified user. Assuming the key exists, it’s used in the next steps.

  • Steps 5–6: The server creates a message including some identifying information about the credentials that live on the client authenticator, as well as a “challenge” (a cryptographically random set of characters). This gets sent to the client. The message is encrypted with the public key– that means no one else can read this challenge, because no one else has the corresponding private key.

  • Steps 7-8: The web application asks the browser to pass the message to the appropriate authenticator.

  • Steps 9-10: The authenticator asks the user to unlock with a biometric, if appropriate.

  • Step 11-12: If biometric unlock was successful, the authenticator uses the private key stored on the device to:
    ‣ Decrypt the challenge with the private key
    ‣ Re-encrypt the challenge with the private key (This means that it can only be successfully decrypted with the corresponding public key)
    ‣ Send the encrypted challenge and metadata back to the web application

  • Step 13: The web application sends the message back to the server.

  • Step 14: The server validates the message from the web application, using the public key stored in the register step.
    ‣ The server decrypts the challenge with the public key and compares it to the challenge we originally sent to the client. If the challenges match, it’s because the correct client/authenticator successfully “unlocked” and “locked” the challenge and sent it back.

  • Step 15–16: The server tells the client whether the user was successfully authenticated or not, and authentication is complete.

Putting It All Together

Now that we are comfortable with how the registration and authentication flow work, we can summarize the work we need to add passkey capability to a web application.

‍Modifying a web application to use passkeys generally requires the following things: ‍

  • Adding 4 endpoints to the server. Notice that both the registration and authentication flows require two calls to the server. These are common to think of as “preRegister”, “register”, “preAuthenticate” and “authenticate”.

  • The client/web application needs to handle that middle part of making the first server call, communicate with the browser/platform, make the second server call, and then handle the result of the register/authenticate process.

  • Store and retrieve public keys on the server.

  • Do the cryptographic challenge generation, signing, etc as part of the two ceremonies.

    That summarizes the work to be done, but of course, the devil is always in the details. It’s one thing to get a reference implementation built, but once you have the basics in place, you need to of course consider scalability and reliability. Additionally, to improve the usability of passkeys for your users, you’ll want some more features such as the ability to add and remove multiple authenticators (or, sets of passkeys), which requires some overhead around managing the metadata of the authenticators for your users.

Top comments (0)