Magic link authentication trades the password reset flow's pain — the most abandoned flow in most apps — for making that exact experience the entire login process.
A magic link is a passwordless authentication method where a user enters their email, receives a one-time link, and clicking it logs them in — no password to remember, no password to leak in a breach. It's effectively "forgot password" made into the primary flow instead of the recovery flow, which is a large part of why it feels so familiar to users the first time they encounter it.
Why Magic Links Matter (and When to Skip Them)
Magic links eliminate password-related support burden entirely — no "forgot password" flow needed, no password strength requirements to enforce, no password database to protect against credential-stuffing attacks. For consumer apps with infrequent logins, this trade genuinely improves both security posture and conversion, since users don't abandon signup over password requirements.
Skip magic links for apps needing frequent, fast re-authentication (the round trip to an inbox adds real friction for high-frequency use) or where email deliverability is unreliable for your user base — a magic link that lands in spam is a broken login flow.
Getting Started with Magic Links
Request and verify flow:
import { randomBytes } from "crypto";
async function requestMagicLink(email: string) {
const token = randomBytes(32).toString("hex");
const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes
await db.magicLinkTokens.create({ email, token, expiresAt, used: false });
const link = `https://yourapp.com/auth/verify?token=${token}`;
await sendEmail(email, "Sign in to Your App", `Click to sign in: ${link}`);
}
async function verifyMagicLink(token: string) {
const record = await db.magicLinkTokens.findByToken(token);
if (!record || record.used || record.expiresAt < new Date()) {
throw new Error("Invalid or expired link");
}
await db.magicLinkTokens.markUsed(record.id);
return createSession(record.email);
}
Core Magic Link Concepts Every Developer Should Know
Tokens must be single-use and short-lived. A magic link that works repeatedly or never expires is a standing credential anyone with access to the user's inbox (or a forwarded email) can use indefinitely. 10-15 minutes and one-time use is the standard, safe default.
Tokens need to be cryptographically random, not predictable. Using crypto.randomBytes (or equivalent) rather than a sequential ID or weak random source prevents an attacker from guessing valid tokens.
The email itself is a real attack surface. If an attacker gains temporary access to a user's inbox (a common outcome of separate account compromises), they can request and use a magic link without ever knowing a password. Fix: treat magic link security as tied directly to email account security, and consider requiring a second factor for high-value actions even after magic-link login.
Link-clicking behavior varies by email client — some corporate email security scanners "click" every link in an email automatically to scan for malware, which would consume a single-use magic link before the real user ever sees it. Fix: for the initial click, show an intermediate confirmation page ("Click here to complete sign-in") rather than completing auth on the raw link click, so an automated scanner hitting the link doesn't burn it.
Common Magic Link Mistakes and How to Fix Them
Mistake 1: long-lived or reusable tokens. This is the most common magic link security mistake — treating the link like a permanent bookmark instead of a one-time credential. Fix: enforce both short expiry and single-use at the database level, not just in application logic that could have bugs.
Mistake 2: not rate-limiting magic link requests. Without limits, an attacker can spam a victim's inbox with login link emails, or use the endpoint to enumerate valid email addresses based on response timing/behavior differences. Fix: rate-limit by email and by IP, and return identical responses whether or not the email exists in your system.
Mistake 3: sending the token in a way that leaks via referrer headers or logs. A token in a URL query parameter can end up in server access logs, browser history, or leak via the Referer header if the destination page loads external resources. Fix: use POST-based confirmation where practical, and be deliberate about what the verify page itself loads.
When Should You Use Magic Links Instead of Passwords or Passkeys?
Use magic links for consumer apps with infrequent login needs, or as a lower-friction alternative for users unfamiliar with passkeys. Prefer passkeys where phishing resistance matters more (magic links can still be phished if a user is tricked into forwarding or sharing the link) and passwords/traditional auth where offline or frequent re-authentication without email round-trips is required.
Magic Links in Production
Monitor email deliverability closely — a magic link is only as reliable as the email actually arriving promptly, and spam filter false positives directly break your login flow in a way password auth never would. Also consider pairing magic links with passkeys as a progressive path: magic link for first login, prompt to register a passkey immediately after, moving frequent users to a faster, more phishing-resistant method over time.
If password reset is already your most common support ticket, magic links are worth piloting — you're likely already paying most of that "email round trip" cost anyway, just at the wrong point in the flow.