Passkeys: the end of passwords and phishing




June 12, 2024



We’ve been using passwords since before we even had computers, the Romans had their watchwords [1] and even prohibition-era speakeasies relied on them to grant entry. In the modern world, any person who ever touches a computer knows what a password is. Every hacking scene in a movie involves someone guessing a password until the big “Access Granted” alert pops up followed by a moment of celebration and relief. 
Within the security industry, passwords are the best solution we have to the authentication problem. Do we love passwords? Not really, they have a lot of problems and users usually hate them. However, the test of time has proven that passwords have been good enough so far.
The main issue with passwords is that users need to remember them, and because we authenticate daily to multiple applications, we end up using (and reusing) easy to remember passwords. There have been multiple attempts to authenticate users without needing a password, but none of these attempts has gained widespread adoption.
Somewhat recently, a promising solution has been in the works. We’re talking about passkeys [2], a new type of credential based on public key authentication and the use of consumer devices (like a smartphone) to authenticate users. If passkeys achieve widespread adoption, then we might enter a new era in application security where phishing is a thing of the past.

Why haven't we been able to get rid of passwords?

Everyone knows that using your dog’s name as a password is not the best idea, or that using 1234 as your debit card PIN is not the smartest thing to do. However, normal people (not like ourselves paranoid cyber-folks) don’t enjoy having to remember complex and unique passwords, nor having to deal with password managers. The result? They use their dog’s name for their work email and 1234 as their bank’s PIN. 

As an industry we believe that this can be fixed with more training and awareness, which is true to some extent. However, assigning blame to someone who got phished or had their password guessed because of their lack of knowledge and awareness is not very fair. Why does someone with a non-technical background have to understand the nuances of URLs, HTTPS certificates, and entropy?

Our responsibility as security professionals is to provide solutions that present minimal friction to users, and passwords have been the Achilles’ heel and the most in-your-face security control that we offer (i.e. impose on) users. So, when we think about awareness and training as a way to prevent phishing, we can’t forget that if someone got phished, it’s because we offered them an authentication mechanism that was not robust, and not because the user was naive and fell for a trap. 

When we think about replacing passwords, it needs to be with something that offers better usability, and provides net security benefits. So far, nothing was able to fulfill these requirements. The solutions we tried either required special devices, or required complex setups that hindered the user experience.

Today, with the current technological landscape, in particular with widespread access to powerful and capable devices, there is hope that we might be able to give it another shot. 

Since 2013, the FIDO Alliance [3] and the World Wide Web Consortium (W3C) [4], in collaboration with the industry, have been working on a specification (WebAuthN [5]) that leverages the modern technologies available on consumer devices to enable applications to authenticate users without ever needing a password or any complicated setup. Next, we’ll dive into this new solution that brings the promise of making passwords a thing of the past.

Introducing passkeys

As a result of the joint effort between the FIDO Alliance and the W3C, the WebAuthN specification was developed and implemented by all major browsers. 

WebAuthN is a browser API that allows application developers to use public key-based credentials for authentication, without ever using a password. These credentials are phishing-resistant, and offer multi-factor controls without the need of specialized hardware, by taking advantage of the modern browser, operating system and mobile platforms security features. 

Passkeys are computer generated (therefore always strong), are phishing-resistant and are designed in a way where there are no shared secrets between the client and server. They offer a clear benefit from a usability standpoint, as users don’t need to remember passwords and can use biometric authentication mechanisms built-in their devices, such as TouchID or FaceID to authenticate to web applications. Passkeys also offer a significant security improvement, as they offer two authentication factors by default (something the user has, and something the user is) in a seamless way. 

So what is a passkey and how does it work?

As with other things in security, passkeys are built upon the pillars of public key cryptography. There are two components for every passkey, one public key that is stored in the server and is associated with the user account, and a private key that only the user has in their control. This private key will be stored in a dedicated secure device (called Authenticator) such as a Yubikey, a secure enclave module (TPM), or in iCloud Keychain or Google Password Manager. Even though the private key is in control of the user, the device where it’s stored should not allow retrieval of the private key, and should only offer signature primitives to sign the challenges using the private key. This way, it is guaranteed (assuming no vulnerabilities in the device) that the private key will always be protected and could not be compromised by external attackers.

How does logging in with a passkey look like from a user’s perspective?

It’s actually pretty neat. Following we’ll show you how registration and authentication works, using the [6] demo site (specifically developed to showcase passkeys).


The first step is for the user to visit the page they want to create an account on, and indicate their username:

webauthn user registration

In our example, we’ll be using the refactor_security username. The user then clicks on the Register button. After doing so, a popup with a QR code appears on the screen:

This popup gives two options to the user:

  • Scan the QR code with their phone to create the passkey in the device, or
  • connect a USB key (like a Yubikey) to create the passkey there.

In our example, we’ll use an iPhone. So, next, we scan the QR code using the phone’s camera and we see the following popup on the phone:


By default, iPhone allows creating and storing passkeys in iCloud Keychain, and because our phone has FaceID we’ll go ahead and use that (you could also use TouchID). After the passkey was created, the public key was sent to the application, and the account was created:


After creating the account, we can proceed and test out the authentication process. So, we type in our username and hit Authenticate:

Same as it was when registering the account, when authenticating we also get a popup with a QR code that we can scan with our phone:

The only thing we need to do is hit Continue and authenticate with FaceID. After doing so, we see the following in the app:

Authentication was successful, and we can see how the app was able to access the details of the user account. 

Amazing, right? The user did not have to come up with a weird password, and did not have to do anything other than unlocking their phone. From the user’s perspective it was a seamless experience; in the background, a lot of interesting stuff was happening.

On a technical level, and according to the specification, the registration and authentication processes are called Ceremonies, and entail different operations by both the application (formally called the Relying Party) and the user (Client/Authenticator). 

During registration, the application will send a request to the client to create a WebAuthN credential. The client (usually the browser) will then communicate with the user’s device of choice (the Authenticator) to create this credential. The credential is a public and private key pair, of which the private key is stored in (and never leaves) the device, and the public key is returned to the application through the browser. The application will create a new account on the backend, associating the username with the provided public key. 

When authenticating, the user provides the username they want to authenticate with, and the application will generate a challenge that will be sent to the user to prove their identity. The client (browser) will then forward this challenge to the authenticator to solve. This challenge is solved by signing it with the private key associated with the public key of the user account. The browser will then relay back the solved challenge to the application. User authentication succeeds if the application is able to verify the signature of the challenge with the user’s public key. 

The following diagram illustrates the different actors involved in these processes:


During both registration and authentication, no secrets were shared between the user and the application, and no particularly sensitive information was transmitted over the wire. Additionally, the authenticator offered a couple of guarantees that further add to the security of the solution: presence and consent. The authenticator verified that the user was present at the time of registration/authentication by requiring the user to tap the device, and also received consent and verification from the user by having them use a gesture such as FaceID, present a fingerprint, or a PIN/password (local to the device). 

Because of the way passkey authentication works and the security features it offers, we can effectively prevent most common phishing attacks. This can be one of the biggest security gains we’ve seen in decades. How does it prevent phishing? Because of the following features:

  • Passkeys are scoped to a specific domain: if I create a passkey for, then the authentication flow will programmatically check if I have credentials for exactly This is done by the browser, and the authenticator, not by the user. Therefore, an attacker who tricked a user into visiting (with a capital “i” instead of an “L”) won’t be able to steal their credentials, as the browser/authenticator will not find a credential for that fake domain.
  • There are no shared secrets: passkeys are basically a public and private key pair. The authenticator devices are designed in such a way so that the private key can not ever leave the device, not even in the event of physical compromise. Therefore, there is no way for the user to send the private key to the attacker.
  • Passkeys offer multiple factors by default: to authenticate using passkeys, users need to provide at least two factors: something they have (the authenticator device), and something they are (the biometric verification) or something they know (a PIN).
  • Physical proximity between client (browser) and authenticator: the authentication flow is designed in such a way where the authenticator needs to be in physical proximity to the client. This is verified by one of two ways, depending on the type of authenticator being used. If it’s an USB key, then the fact that it’s connected to the computer proves that the device is indeed nearby. If it’s a phone, then there’s a protocol based on Bluetooth Low Energy (BLE) to ensure the phone is close to the computer running the browser. This means that even if the attacker is able to trick the user into performing all the gestures (such as authenticating with FaceID), the fact that they’re physically distant will result in a failed authentication attempt.

These features offer robust controls around the authentication flow that render the phishing attacks as we know them completely useless. This is an extremely amazing feat, and having all these protections work in the background in a seamless way offers a lot of hope into imagining a future where phishing is a thing of the past.

Are passkeys easy to implement?

Modifying an existing application to use passkeys can present some challenges. The biggest one is what to do with existing users, who are using passwords to log in. What most developers do is offer both authentication mechanisms so users can slowly migrate towards using passkeys. This is a challenge from the user experience (UX) perspective, as the login form will need to show the different options. All this will need to be done with minimal friction.

For new users, the organization needs to decide if users will first be prompted to use passkeys, and have password as a legacy option. Again, the user experience and interface for all these flows is very important. Both to promote adoption of passkeys, and also reduce friction for new users to onboard the application.

On a technical level, application developers will need to make changes both in the front and back end of the application. On the frontend, there will need to be new JavaScript code that will use the browser’s WebAuthN API to issue credential creation requests, and obtain authentication assertion responses. On the server side, the database will need to be modified to contemplate the storage of user public keys and other passkey-specific attributes. Additionally, code to generate and validate the authentication challenges will need to be implemented.

As with most critical features, it is not the best idea to roll your own implementations. There are multiple libraries [7][8], for the most popular languages, that implement the passkey specification and are compliant with the FIDO2 conformance tests [9]. Using these libraries should not present significant challenges, but should be handled with care as authentication is a very critical aspect of any application.

It is important to note, that implementing passkeys will not offer any session management features, nor offer any type of authorization controls. All these critical features will need to be a separate implementation, as passkeys are only meant for authentication.

Final thoughts

To wrap up the blog post, we wanted to offer our thoughts regarding what we think about the following question:

Will passkeys finally replace passwords?

We really hope so. The net security and usability gains can not be ignored, and if we end up eliminating phishing then it is definitely worth the effort. Additionally, we are in a moment where the majority of devices are very capable so we do have the infrastructure to make this a reality. However, even if the technical aspects are all aligned, the success of passkeys will mostly depend on how we manage to solve the user experience. It is true that most users dislike passwords, but what’s worse than passwords is having to learn new things and change the way you were doing things. Passwords have a big advantage in the sense that everyone knows what they are for and how to use them. It might be difficult for a non-technical user to understand how passkeys work. It is our job to effectively communicate the concepts, the benefits, and develop applications and user experiences that make passkeys a source of joy.


1. Histories:
2. Passkeys:
3. FIDO Alliance:
4. World Wide Web Consortium (W3C):
5. WebAuthN:
6. WebAuthN Demo Site:
7. WebAuthn Awesome:
8. Libraries:
9. Conformance Self‐Validation Testing:

At Refactor Security, our team of application security experts can help you in your passkeys implementation project. We do not endorse any particular product or vendor, so we are only concerned with whatever the best solution to a particular problem might be.

Get in touch with us if you want to learn more or if you need any help with anything related to passkeys.