Email + password authentication should be a last resort (rant)
Authentication
If you’re working on a web product, odds are one of the first decisions you’ll make is how users will sign up and log in (aka “authentication”). Unfortunately, the authentication method most developers reach for by default is arguably the worst one.
Why email + password auth sucks:
- People often use several email addresses.
- Passwords tend to get reused. Some random insecure site has a leak? Your users might also be vulnerable.
- Password rules often feel arbitrarily complex. “
Minimum 8 characters
+sOmE UpPeRcAsE
+at least one digit
+at least one symbol
BUT ONLY CERTAIN ONES + …” These are especially fun when you only find out the rules after submitting the form.
My password isn’t weak—your auth system is. - People forget their passwords all the time. It’s often faster to just use the reset password flow as if it were a “magic link” login than to guess and check.
- You typically need to get users verify their email address—an annoying extra step both from the user’s perspective and implementer’s perspective.
- It’s so bad it led to two-factor authentication (2FA).
And why should users trust that you’ve set up your backend in a secure enough way to never leak their credentials? The answer is that they shouldn’t, which means the only reasonable option you give your users is to generate a unique random password for every website.
Power users (not the average person) love to boast that they’ve figured it all out with their password manager of choice. But even those are flawed. If you’re on any other device, say logging in from a friend’s house, or god forbid from a friend’s phone, the pain of entering a secure 50-character generated password can’t be understated. And your password manager won’t save you from phishing attacks or man-in-the-middle (MITM) attacks on insecure sites.
So, let’s consider the alternatives and their trade-offs. Because, unfortunately, there’s no silver bullet.
Social login
Social logins solve a handful of problems. I’ll trust Google to not store passwords in plain text, but probably not your random website (sorry). More importantly, the fewer accounts and passwords I need to remember, the better.
But they introduce other problems. Let’s look at some pros & cons:
Pros:
- Secure as long as the upstream third parties know what they’re doing. (Sometimes, they don’t!)
- Reuses an account users are already logging into regularly. Avoids proliferation of accounts.
- Not tied to one particular device.
- Doesn’t require second verification step.
Cons:
- There’s often no distinction between logging in and signing up. If you forgot which email address you originally signed up with, attempting to log in with a different social account might lead you to create a brand new account.
- You’re dependent on a third party. If Google’s auth server is down, your users can’t log in. If Google decides your site is no longer following their rules (which could be as simple as changing your logo and forgetting to update the logo on their consent screen), your users can’t log in. Did you know Google often takes 3+ weeks to review your oauth applications?
- Privacy concerns. Not everyone wants Facebook and Google tracking their users.
(Source)
Overall, I’m giving this one a 👎. But only because we’ve got better options today (read on). The UX for social login is still leaps and bounds better than email+password.
License keys
Back in the olden days we used to just buy software and use it without needing an account. You could buy MS Word at Walmart. How? Because the product being sold is a license key. Services can still support tiers, upgrades, and downgrades with this pattern. But not many use it today. Those that do will often sell the license key after you’ve already set up an account using one of the other methods.
(For what it’s worth, Smudge.ai sells just the license key, no accounts.) I stole this idea from Mullvad VPN who allow you to pay just for a license key (“account number”) without any formal signup process.
Pros:
- Simple, great UX.
- A generated license key will be a better credential than whatever password most users are coming up with.
- Fun fact for hackers: guessing only the 25 most common passwords will get you access 10% of the time (source).
- Supports offline authentication.
- Doesn’t require a second verification step.
Cons:
- Users still need to keep track of a credential.
- Easy for users to share (or lose) their credential.
- Prone to phishing / MITM.
- Poorly generated keys can be guessable.
- Not viable for all types of apps.
Overall: 👌 when you’re just selling access to a tool (like a VPN or a Chrome Extension, as opposed to a social network), this is a pretty user-friendly pattern.
Magic link or email code
Meh.
Pros:
- No need to remember a password.
- Doesn’t require second verification step.
Cons:
- Assumes users always have easy access to their email or phone. (At signup, that’s a fair assumption. For login, less so.)
- Can’t assume delivery will be instantaneous. Imagine a 60-second loading spinner in your login form. Awful. Yet waiting a minute for an email to arrive isn’t uncommon.
- Awkward UX: opens a second logged-in tab, forcing the user to close the original tab.
Haters will say another con is that magic links are insecure if your email is compromised. In reality, this is no different from an email+password “forgot password” flow.
Overall, 🥱.
Webauthn
Arguably the best option we have today, and the main reason I decided to write this post. The “Web Authentication API” (webauthn) is a relatively new API built into all major browsers. Webauthn makes it possible to log in using Touch ID or your device’s equivalent.
Pros:
- Secure. Browsers implement public key crypto so individual websites don’t end up rolling their own.
- Good UX. Webauthn allows users to sign in really fast with passwordless options, such as Touch ID or Face ID.
- Doesn’t require a second verification step.
Cons:
- Typically tied to one device or device family.
- More difficult on public devices. Users might need to use their phone to complete signup/login.
- Lack of familiarity. Users trust social logins and email+password forms, but webauthn is new.
- Similar to license keys, webauthn won’t give you an email address or phone number which you can use to
annoycontact your users. - Complex and still annoying to implement. Your average web dev (me) does not want to read up on or make decisions about things like:
relying party
/attestation type
/resident key
/challenge buffer
/authenticator attachment
/CBOR decoders
/ which cryptographic algorithms to support / etc. Just give me some reasonable defaults and a nice API.
To nip this in the bud: “it’s not secure if your device password is stolen.” Sure, but your device password probably also grants access to your email, which itself grants access to basically all your other accounts.
Despite the cons, I think webauthn (perhaps with a nicer API wrapper for us mortals) is an excellent choice to use today. Caveat being a possible early adopter tax: you might want to also implement one of the other auth methods as a fallback until users gain familiarity with this authentication method.
Overall, 🤙.
In summary
Just don’t use email+password. I’m probably giving your app a throwaway email anyway or (ab)using your forgot-password flow as if you supported magic links. There are so many better options today. If you must use email+password, then support any of the other alternatives as well. And give webauthn a shot! My selfish hope is that as more developers adopt webauthn on their sites, better standards/tutorials/wrappers will emerge, making it easier for me to add it as an auth option for my current and future projects.