Passwords are the worst part of most signup flows: users forget them, reuse them, and abandon forms over them. Passwordless login, most commonly the “magic link” emailed to the user, removes that friction and, done right, is more secure than the password it replaces. It’s become a default for a reason.
But “email someone a link that logs them in” hides real subtlety. Get the token design wrong and you’ve built an account-takeover vector. Here’s how to add passwordless auth that’s both smooth and sound.
How the flow actually works
- User enters their email.
- You generate a cryptographically random, single-use token, store its hash with an expiry and the target email, and email a link containing the raw token.
- User clicks; you look up the token by its hash, check it’s unexpired and unused, mark it consumed, and start a session.
That’s the whole thing. The security lives entirely in step 2’s details.
A prompt to scaffold it correctly:
Implement magic-link passwordless login. Generate a cryptographically random token, store only its hash with a short expiry (10-15 min) and single-use flag, and email the raw token in a link. On click: look up by hash, verify unexpired and unused, atomically mark consumed, then create a session. Add rate limiting per email and per IP. Walk me through the token and expiry design before writing the handlers.
The details that make it secure
- Store the hash, never the raw token. Same principle as passwords: your database should be useless to an attacker who reads it. Hash the token (SHA-256 is fine here since the token is high-entropy) and compare hashes.
- Short expiry. 10-15 minutes. Long enough to walk to email, short enough that a leaked link (forwarded, logged, cached) is usually already dead.
- Single use, atomically. Consuming the token must be atomic, mark-and-check in one operation, or a race lets a link work twice. This is the bug that turns “convenient” into “account takeover.”
- Rate limit hard. Per email and per IP. Without it, your login endpoint becomes an email-spam cannon pointed at arbitrary addresses, and your domain’s sender reputation pays for it.
- Don’t leak account existence. Show the same “check your email” message whether or not the address has an account. Otherwise you’ve built an account-enumeration oracle.
- Bind the session to the click, carefully. Beware opening the link on a different device than where the login started; decide whether that’s allowed and message it clearly.
The honest tradeoffs
Passwordless isn’t strictly better in every dimension, and pretending otherwise leads to bad decisions:
- Your auth is now only as strong as the user’s email. If their inbox is compromised, so is your app. For high-security products, pair magic links with a second factor.
- Email deliverability becomes critical infrastructure. A magic link in spam is a locked-out user. Warm your sending domain, use a reputable provider, and monitor deliverability.
- Latency of email adds seconds to login. Fine for most apps, occasionally annoying for frequent logins, which is why many products pair magic links with longer-lived sessions.
Add it without locking existing users out
If you already have password auth, this is the part that needs care: you’re changing how people get in, and the failure mode is a user who can’t log in at all. That’s the highest-severity bug an auth change can have.
So introduce it side by side, gradually:
- Ship passwordless behind a flag, as an additional option, not a replacement. Existing password login keeps working untouched.
- Enable magic links for new signups first. New users have no password habits to disrupt, and you get real deliverability and conversion data on a low-risk cohort.
- Offer it to existing users as an alternative once you trust the flow, still leaving passwords in place.
- Only consider deprecating passwords after the passwordless path has proven itself across a wide, representative slice of users.
Gating each step means that if deliverability turns out to be shaky, or the token flow has an edge case on some email client, you contain it to a small group and roll back instantly, instead of discovering it when your whole user base can’t sign in. With authentication, the blast radius of a bad launch is “nobody can use the product,” so the ability to turn a new auth path off in one click without redeploying is exactly the safety net you want.
Passwordless login is a genuine UX and security upgrade. Nail the token design, respect the tradeoffs, and introduce it alongside what you have rather than in place of it.
ShipSilently lets you roll a new auth flow to new signups first, then widen it, and kill it instantly if deliverability wobbles, all as edge-evaluated flags. Start free.