WebAuthn vs Passkeys

WebAuthn vs Passkeys

In case you heard about Passkeys and WebAuthn, you might wonder what are the differences, or their relationship. This article tries to clarify what both are and shares some personal opinions about the implications of Passkeys.

What is WebAuthn?

WebAuthn is a specification. It is an "RFC" issued by W3C, standing for "Web Authentication" to specify a set of interfaces for browsers to implement.

How does it work?

Fundamentally, the protocol's concept is rather straightforward.

During registration, the device (called "authenticator") generates a cryptographic key pair. The public key is sent to the server and the private key is safely stored locally.

During authentication, the server then asks the client to sign a message with a nonce (called "challenge") with its private key pair. This signed message with the nonce can then be verified by the server using the public key obtained through registration.

Moreover, the private key was never exposed. The signing of the message is done directly by the "authenticator", the device, and protected by some form of local user verification (like fingerprint, face, local PIN, swipe pattern, etc).

This had really strong security properties because the private key was hardware bound, and needed user's local verification to access it.

Why did I use the past tense? Because of ...Passkeys!

What are Passkeys?

Passkeys is basically the platform's implementations of the WebAuthn. Until now, the protocol had a shortcoming: if the user lost their device, they lost the private key and were locked out of their accounts. Bam!

The websites and users would have to either let them register multiple devices, with an associated key pair each, or rely on a (possibly less secure) account recovery mechanism.

To circumvent that, Apple, Google and Microsoft decided to go forward with "Passkeys". This is basically nothing else than WebAuthn but they sync your private keys into the cloud. Your private keys are not tied to the device anymore, they are "backed up" in the cloud, as they say.

It's like handing over a copy of your keys to Apple/Google/Microsoft saying "Here are my keys guys, keep it safe!". This is both a boon and a curse. On one hand, the users don't have to worry about losing their keys. On the other hand, it has of course strong implications on security, privacy and vendor lock-in.

Security-wise, the attack surface becomes bigger: on the device level (since it goes in an out of the secure hardware key store), on the network level by intercepting the syncing mechanism, on the vendor level in case of data breach and on the recovery level with someone trying to impersonate you.

Privacy-wise, they have your keys. Whether it's for their purpose, because of the NSA or whatever agency, they could access all your private accounts. That's a question of thrust here that they don't do.

Regarding vendor lock-in, if they have all your keys and you want to switch the platform ...well, you got a problem. You would probably have to re-register or launch recovery procedures on most accounts. It's quite a pain, and more sneaky since it only becomes obvious once it's too late. If keys were not synced, websites would put more effort into supporting multiple keys per account, thus being cross-platform by default. But with Passkeys they'll likely prefer to let the platform handle it.

Passkeys in practice

The main issue is also that you cannot opt in or out. The WebAuthn protocol lets the platform dictate. It was also raised in this issue that this is problematic: reduced security guarantees, regulations that cannot be applied, no way to block insecure device models, etc... However, the spec is driven by the big player's implementations rather than the other way around.

The other issue is that, in reality, it turns out to be more complex for websites to deal with ...at least, if you want to do it properly. Before Passkeys, you just had to let the users register multiple devices or have sound recovery mechanisms. Now, websites have to deal with devices that are maybe synced, or maybe not, or maybe not yet. Perhaps the user used a hardware key, which is not synced, or disabled it somehow if the platform permits it, or simply hasn't synced the key yet. In other words, there are more cases to take into account while still needing the same safety measures to avoid that a device loss leads to account "lock-out".

Lastly, these security, privacy and vendor lock-in effects are not recognized by average users. They just want to sign in. It is our duty as developers to deal with these issues responsibly.

WebAuthn in practice

In practice, it's a mess. The specification is overly complicated, long, unclear and there is a clear gap between the specs and implementations.

For example, let me cite the second sentence of the abstract.

Conceptually, one or more public key credentials, each scoped to a given WebAuthn Relying Party, are created by and bound to authenticators as requested by the web application.

Well, it's simply not true anymore since mid-2021 and noted in an issue but the specs remains unchained until now.

So, the specs differ from implementations and every platform and browser will deliver you another experience... which is IMHO still seriously lacking. Moreover, "Open" Browsers like Firefox are struggling and lagging behind with partial implementations due to the complexity of the specs, Linux as well...

So, although it's great on paper, the practical experience is a hit-or-miss thing. As it stands now, I strongly recommend to offer an alternative sign in experience if WebAuthn isn't properly supported or if "it doesn't work properly" on the user's device.

Moreover, it's not for the faint of heart. As a developer, you will have to deal with ArrayBuffers using a CBOR encoding and lots of low-level things. The whole process is not simple either, for example, registration is described as a 26 step procedure and authentication requires 23 steps to verify. Have fun! (sarcastic tone)

Conclusion

In my humble opinion, WebAuthn is an awesome concept with terrible execution. The promise is to get vastly improved security and convenience in the same package. However, what you get is a spec that a normal person cannot read, incredible complexity for developers, and browser implementations that are sometimes not working as expected or with poor UX. So here goes your vastly improved security with the touch of a finger ...down the drain. It's just a lot of painful work to get it right properly.

Moreover, it feels like the "big players" move to Passkeys was mostly a hype attempt ...and to pursue their own agenda of user retention rather than being truly helpful to the developer community. They wanted a new start, to remove the hurdle of multiple keys per account and encourage adoption that way. However, it does this at the cost of security, privacy and lock-in, so while useful it is a steep price. Moreover, "rebranding" the struggling WebAuthn specs as Passkeys rather adds to the confusion while not resolving the core problems, namely the complexity of the protocol itself.

So what's my take on it? If you have sufficient resources and time to pour into this, yes, you should support WebAuthn/Passkeys. It is better security-wise and depending how it's implemented, it might be more convenient too. However, if you do not, use an existing authentication provider. Using OpenID/OAuth2 is really much simpler than WebAuthn. You can also combine both by using Passwordless.ID for example, it's a public free identity provider offering passwordless authentication using WebAuthn. Try it if you want.

Thanks for reading and feel free to share your opinion!