A Crash Course in Passkeys and WebAuthn

Delete all your passwords!

James Collerton
9 min readJan 18, 2024
The future is now

Audience

By employing passkeys we can log into web accounts using biometrics (such as a fingerprint or face Id), or a device screen lock code. They remove the need for passwords, MFA, authenticator apps and all other ‘log in’ technologies.

Within this article we explore:

  1. Passkeys: A new type of credential, replacing passwords. We can use these within applications to verify our identity.
  2. WebAuthn: The specification telling us how to use passkeys to replace passwords. This document defines the parties, APIs and interactions required.

There are different groups, all interested in passkeys, but each with their own emphases. For example:

  1. An application wishing to allow biometrics or a screen lock code as a login method. Think Google allowing you to login with face Id.
  2. Browser or user agent developers. User agents act as the intermediary between the application code and the platforms required to store and protect passkeys.
  3. Those writing platforms for storing and protecting passkeys (e.g. OS developers).

Within this article we will mainly focus on group one. For the other two, we will mention how they relate to the specification, but won’t focus there.

To get the most out of this article it would be best to understand public/ private key cryptography, and basic web programming. However, I’ll try and summarise the main concepts as we go, so hopefully you can still follow along!

Argument

Remembering passwords is hard. If you’re like me you have thousands of accounts, and even with a password manager authentication is an arduous process.

As we’ve seen over the years, passwords are not completely secure. Data breaches set companies back millions, and at one time cost me £23.99 for a software package stolen via my Amazon account. Unacceptable.

To circumvent this the FIDO (Fast IDentity Online) Alliance (an association including Google, Microsoft, Amazon etc.) have introduced passkeys, a credential capable of authenticating you on your phone or computer via biometrics or a screen lock pin.

For example, if you’re accessing a website on your computer, just unlocking your phone can log you in.

Passkeys aim to go further than removing passwords. They are designed to eliminate MFA, SMS OTP messages, authenticator apps and other access aids.

Additionally, they will make the world simpler. No password managers, or fumbling for verification emails!

This is a really important point. The majority of progress in the authentication space has increased security, but not ease of use. Passkeys do both. Due to this, and the investment of all the big players, they may well catch on quickly, and cause a significant shift in the space.

Setting up our first passkey

Let’s dive right in with an example. I’m going to set up and use a passkey for my Google account.

In the below screenshots, taken on my phone, we can see Android has automatically set up a passkey on my handset. By hitting ‘Use passkeys’ I’m given the option to try it out.

Setting up my Google account for passkeys on my phone

Now let’s move to my laptop, and log in using the passkey on my phone.

I go to the Google login page on my computer, and when prompted for my password select the passkey option.

Login flow on my laptop.

I’m then shown a QR code to scan with my phone. This connects my handset to my laptop via bluetooth.

Connecting the phone and laptop

In the last step I’m prompted to enter my Android pin on my phone (not pictured as you can’t screenshot due to Android’s security policy), finally I’m logged into my laptop!

Final steps until I’m logged in!

Unpicking the relationship between FIDO, WebAuthn and passkeys

There are a lot of groups and standards involved in using passkeys, and how they are referenced is often quite confusing. Let’s clarify the main players.

The FIDO Alliance is a group of representatives from major companies with the mission of reducing reliance on passwords.

As part of their work they publish a number of standards which can be split into two groups: ‘user authentication specifications’ and ‘device onboarding specifications’. This article is only interested in the first of the two.

The user authentication specifications include the ‘Client to Authenticator Protocols (CTAP)’ spec. CTAP is complementary to WebAuthn, as we’ll see shortly. Both together are called FIDO2.

WebAuthn is a specification written by W3C in collaboration with the FIDO alliance, and also forms part of the ‘user authentication specifications’. It is designed to replace passwords with a new credential type — passkeys!

Confused yet?

Technical details

From this point onwards we’re going to dive into what’s going on behind the scenes.

WebAuthn at a High Level

Passwords are bad, and WebAuthn is the specification for replacing passwords with a public/ private key pair (also known as a passkey).

For those who haven’t heard of public/ private key cryptography: there are two pieces of data involved. A public key you can share with anyone, and a private key you keep to yourself.

The way it works is complex. However, butchering the details, you generate a sort of signature with your private key, which you send to holders of the public one. They check the signature comes from the private key using the public key and some clever maths. If it verifies, as only you have the private part, you must have sent the message!

Within WebAuthn, when you register to a site you generate a public/ private key pair:

  • The private key is stored securely on a device (hopefully with a hardware security module), and can only be unlocked via biometrics or a security key.
  • The public key is scoped (making sure it is only valid for the intended site) and sent to whichever site you are logging into, along with an attestation. The attestation is a way of making sure the key comes from a valid source.

As the public key is useless without the private one, suddenly hackers are no longer interested in exfiltrating passwords from a site’s database. They would need to individually go to each device and steal its private key.

When you try to log into one of your accounts you authenticate, sign something (with your private key), and send it back to the site for validation (done with the public key).

Let’s formalise this description with some definitions (note, an exhaustive list of terminology is found here):

  • Relying party: The application using WebAuthn to register and authenticate users. It is assumed to be formed of a server and a client (defined next). There is also a ‘relying party script’, which is called by the user agent and orchestrates interactions between the two.
  • Client (conforming user agent) and client device (together the client platform): The client provides the API (as defined by WebAuthn) for interacting with the authenticator. The client device is the device where it resides.
  • Authenticator: The entity responsible for generating and protecting your passkeys. For example, on your laptop there may be a dedicated cryptographic hardware entity only unlockable with your fingerprint.
  • User agent: Software allowing an end user to interact with the Web.
  • End User: Whoever we’re authenticating!

An example set up might be I (the end user) want to create a passkey login for the application ‘Videoify’ (the relying party). On my Macbook (client device) I open a browser (the client) and go through the registration process (the relying party script).

As part of this my browser calls a dedicated cryptographic hardware entity only unlockable with my fingerprint (the authenticator), to generate and store our key pair.

An overview of how the different components fit together.

Let’s break down WebAuthn into two parts: registration and authentication.

Registration

The registration flow

This is where we create a public/ private key pair and associate it with a user’s account. Let’s have a look at how it works.

Initially we trigger the script used to orchestrate calls to the client and server. The first thing this must do is retrieve a challenge from the server to avoid replay attacks.

This is then composed into a set of options including the relying party’s ID, the user’s information, and which key types and signature algorithms the relying party supports. This is supplied to the client in order to generate a public/private key pair via navigator.credentials.create().

In return the relying party script gets an AuthenticatorAttestationResponse. This contains the public key, challenge, client data used for scoping, a credential Id, and attestation information required by the relying party server.

It’s worth noting the AuthenticatorAttestationResponse implements the AuthenticatorResponse interface. This is what contains the client data.

The script then sends the attestation over to the server.

The server checks the challenge is the same as the one it is expecting. It validates the attestation information using the attestation statement.

This statement has an attestation signature and attestation statement format. Each format has its own verification procedure.

Scoping (making sure a key is only valid for a specific site) works as when the client calls the authenticator for registration it passes along the site’s origin, which is stored alongside the credential Id. This is also baked into the authenticator response.

As we will see in the next section, when a client calls the authenticator for authentication it passes the origin again, meaning that we can only unlock keys for the same one.

This origin is also verified by the relying party server. For example, if someone created a passkey on malicious-site.net and not relying-party.net, it may become suspicious.

The credential Id is stored against the public key and identity for use in authentication.

Authentication

The authentication flow

Once we’ve registered our passkey we can use it to authenticate!

To do this, our relying script calls the client, passing along the credential Id. The authenticator carries out the necessary work to unlock the public key (the biometrics or pin), and returns an assertion.

This assertion implements the same AuthenticatorResponse interface as the attestation from registration. It contains the signature the relying party server will check to see if we have the private key, and the credential Id so the server knows which user we’re on about!

All of this is then sent over.

The server takes takes the credential Id and looks up the public key, verifying the assertion. If it’s valid it looks up whoever the credential Id belongs to, and completes authentication.

We’ve covered the two core use cases for WebAuthn. We’ve left out things like aborting authentication attempts and decommissioning unused credentials, but they are comparatively straightforward, and are left to you.

What if the client and authenticator are on different devices?

The client and authenticator don’t necessarily need to be on the same device. For example, if I’m logging in on my laptop (the client), but using face Id on my phone to authenticate (the authenticator).

A platform authenticator is one that is part of the client device, whereas a roaming authenticator is not.

Roaming authenticators use ‘standardized cross-platform transport protocols’ like bluetooth (remember our example!) to communicate back to the client device.

Platform authenticators essentially mean your client device enters a zone of trust. Now just by unlocking it you can authenticate to all your accounts.

Roaming authenticators are generally used to set up new trusted devices, or if we don’t want to give out those privileges.

Client to Authenticator Communication: CTAP

The existence of roaming authenticators motivates our final section, which discusses the CTAP spec.

In combination with WebAuthn this defines FIDO2, and it dictates how a client communicates with a roaming authenticator.

As we said at the start of the article, we’ll mainly be focussing on WebAuthn from the relying party perspective. Therefore we won’t dive into how this works. For us, it’s enough to know it’s there!

Conclusion

In conclusion we have covered WebAuthn and passkeys, including their definition, use cases and technical details.

--

--

James Collerton
James Collerton

Written by James Collerton

Senior Software Engineer at Spotify, Ex-Principal Engineer at the BBC