Passkeys are almost awesome
They're a key part of a modern login strategy, but not enough on their own.
There’s been a lot of discussion recently about passkeys – the alternative to passwords for logging in to apps and websites. DHH wrote a piece suggesting they’re more problematic than passwords.Implementation complexity, and John Gruber echoed some of those concerns.
However, I love passkeys! I think they are a great solution to real problems, and they’re capable of offering a significantly better user experience than passwords, two-factor authentication, or logging in through third-party services like Google or GitHub.
Why passkeys are better than passwords
Passkeys make phishing impossible, get rid of two-factor codes, and eliminate the need to save or remember passwords, and offer a one (or fewer) click login experience. They’re an open standard and work with web and native apps. Another security benefit is that if you support passkeys, you also support hardware security dongles – they’re a part of the same FIDO standard.
Passkeys alone aren’t enough
It’s perfectly possible to have passkeys be the only login mechanism for a service. However, almost every service will want to validate the user’s email address – this prevents spam and bots, but most importantly provides account recovery through a secure, well-understood path.
So, for some applications where anonymous user accounts are acceptable, you can get away with passkeys alone. Otherwise, you’ll be collecting an email address.
The same exact flow will work with SMS/text message confirmation if that’s the route you choose to go, but I’ll just talk about email in this article for simplicity.
Since you have to do this, you might be thinking, well, why support passkeys at all? Why not just go email-authentication only? Well, you can. If you pick support one login mechanism, it should be email authentication. Universally understood and secure enough for most situations. Remember: your account email can almost always reset your password, so it’s already the achilles heel of your information security.
But email authentication is annoying, takes time, potentially gets filed in spam, and typically requires copying a code from one device or application to another.
Some people have tried to solve this with “magic links”, where a specially crafted one-time-use URL is emailed to you. I initially thought this might be the best way to do email authentication. Unfortunately, magic links fail spectacularly in some important cases:
For a magic link to work, you need to click the link from the same device you received the email on. This makes logging in to another device nearly impossible. You can try sending yourself the link somehow, maybe with Universal Clipboard or by sending yourself a message.
But you have to be really careful, if something tries to open the link before you, such as an iMessage or chat app trying to load the magic link to provide a website preview card, it can potentially invalidate the link if it’s one-time use.
And if you don’t do that, now you have to log in to your email on that device, which itself might be a whole annoying process.By default, in popular email clients like Gmail for iOS, the link gets intercepted by the in-app browser, which often has its own session separate from your main browser. This is very confusing, and you end up logged into an ephemeral browser that disappears when you hit the back button. And again, if your magic link expires after a single use, you can’t press the “Open in Browser” button to then log in in the browser. This is a tremendously hot mess. These in-app browsers should not exist, they’re nothing but a bag of hurt.
So, magic links are out. We’re left with the most common email login solution: send the user a time-based code, and display a box on your website to let them type that code in. This works okay, solves the above problems, and you can pretty easily implement it by issuing TOTP codes that you email.
Still, unfortunately, you’ve got a couple new pages to design for your login flow.
So why add passkeys on top of email?
Passkeys can serve as a natural extension of the email login flow, and offer all the benefits of a password manager and two-factor authentication, except it’s even easier. Once configured it’s better to login to a website with a passkey in every way.
Autofill in password managers is unreliable, or it’ll log in before you can click “Remember me” or all sorts of weird gotchas. And then entering two-factor is another headache on top of that.
The reason to add passkeys is because it’s a better user experience!
Websites often get it wrong
The main problem with logging in with passkeys is that everybody designs their god damn login screen differently. Sometimes it says “Sign in with passkey”, sometimes it will change based on the device to say something like “Log in with Touch ID” or “Log in with Windows Hello”. Often, it will say the wrong one for the device you’re on.
Sometimes websites will require you to enter your email address before prompting you to log in with a passkey, other times the passkey prompt just appears. Sometimes the passkey prompt appears in the corner at the same time as the login form, so you’re not sure which to use.
Password managers and browsers sometimes get it wrong
The initial setup of password managers is problematic. Because passkeys are an open standard, everybody wants to let you log in.
For example, I use 1Password as my password manager, which has great passkey support. However, let’s say I’m logging in via Chrome on Windows. There are three possible places my passkey could go, each offering completely different UI:
1Password
Google Password manager, the built in thing in Chrome
Windows Hello
If either of the other one pops up, I’m boned and I created a passkey in the wrong spot. If I used Windows Hello, I’m especially boned because I don’t even think that syncs between devices. Also because I have to figure out what Windows Hello is.
Once 1Password’s browser extension is set up, it almost always properly takes precedence and it’s not an issue. But that initial setup is not cool for casual users. (Actually, if you cancel out of the 1Password passkey prompt, the Google one potentially comes up. A bit tricky.)
Browser makers and password managers need to take another crack at these flows, which may require new API, to clarify this confusion. Because passkeys put the browser vendor, operating system, or password manager in control of the most important parts of the login flow, they have a heightened responsibility for nailing this UX.
The ideal registration flow
So, if you were starting a website from scratch today, what’s the best way you could implement login?
With email login and passkeys, your sign up form can be this simple:
Collecting the email address immediately sends the user through the standard email login flow. This confirms their email, ensures you cannot have a user account without a backup strategy, and minimizes what the user needs to input to get signed up.
Once they’ve done that, you can continue setting up the user account:
Once the user account is set up, you can offer the optional ability to create a passkey:
They can skip here if they’re scared, and can always do it later via account settings. They’re already set up with email, so they can always log in. If they hit create passkey they’ll see something like this pop up in their browser:
Managing passkeys
Something that is not obvious about passkeys initially is that your user account can have multiple of them. It’s a key part of the design. This means multiple password managers can log into the same account with different passkeys. Here’s a simple example of the settings UI where you can configure this:
It’s useful to provide the ability to label them, even better if you can pull in the name of the password manager somehow.
The ideal sign in flow
Now, when it comes time to sign in, I recommend just having a typical sign in button somewhere in your navigation, that takes you to a dedicated sign in page. Don’t proceed directly to the passkey, since the user might need to log in via email.
Nothing pops up on this page, just a simple choice. Note that we don’t need any kind of “email recovery” thing, because that is the same thing as signing in. Clean and simple. They can tap “Sign in with passkey” and get signed in immediately without entering any text, email, or user credentials. Just confirm with the OS or password manager. It’s also just as easy to sign in with email as you’d expect.
We should standardize on calling them “Passkeys” and update all language that refers to specific authenticators (or hardware security keys, which we can reframe as a type of Passkey).
Let’s get behind passkeys
Hopefully this demonstrates a login flow that should be robust enough to handle common use cases, and simple enough to work for everyone. With a little standardization on how websites talk about passkeys, we can clean up a lot of the user experience problems of login, and gross two-factor codes.
It’s relatively early for passkeys, but I think we’re close to something really great here.
Did you write this for me? 😉