RestingOwl owl logo RestingOwl

Passwordless Authenticationwith Magic Links

Quick Answer: A magic link is a one-time, time-limited URL sent to the user's email address. When clicked, it authenticates the user without a password. The server generates a cryptographically random token, hashes it for storage, and invalidates it after a single use. No password is ever created, stored, or transmitted.

Magic links have moved from a niche pattern used by Slack and Medium into mainstream authentication. The premise is simple: instead of asking users to create and remember a password, you send them a link that proves they control the email address they registered with. Clicking the link proves identity. No password required.

But simple to use does not mean simple to implement securely. A poorly implemented magic link system can be more dangerous than a well-implemented password system. This guide covers how magic links work, what makes them secure, and the specific mistakes to avoid.

How Does a Magic Link Work?

The flow has four stages:

  1. Request: The user enters their email address and clicks 'Send magic link'. The server validates the email and generates a cryptographically random token using a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator).
  2. Store: The server hashes the token (using a fast algorithm like SHA-256: bcrypt is unnecessary here since the token is already random and not user-chosen) and stores the hash alongside the user's email, an expiry timestamp, and a used flag.
  3. Send: The server emails the user a link containing the raw token as a query parameter: for example, https://yourapp.com/auth/verify?token=abc123....
  4. Verify: When the user clicks the link, the server hashes the incoming token, looks up the stored hash, checks expiry, checks the used flag, and if everything matches, creates an authenticated session and marks the token as used.

The key insight is that the raw token exists only in two places: the email, and the user's browser when they click the link. The server never stores the raw token: only a hash. Even if the database is compromised, the attacker cannot use the stored hashes to authenticate.

Magic Links vs Passwords: Which Is More Secure?

The honest answer depends on your users. Magic links eliminate entire categories of password-related vulnerabilities, but they shift trust to the email channel.

Security DimensionPasswordsMagic Links
Credential theft via database breachHigh risk: hashed passwords can be crackedLow risk: tokens are random and single-use
Phishing attacksHigh risk: users can be tricked into typing passwordsMedium risk: users can click malicious lookalike links
Credential stuffingHigh risk: reused passwords are exploited at scaleNot applicable: no password to reuse
Weak credentialsHigh risk: users choose predictable passwordsNot applicable: no user-chosen secret
Brute forceMedium risk: rate limiting requiredVery low risk: 128-bit random token space
Email account compromiseNot a factorCritical risk: email access = full account access
No internet access at login timeWorks fineFails: email must be accessible

Magic links are strictly better for users who reuse passwords or choose weak ones: which is most users. They are worse for users whose email accounts are poorly secured. For most consumer applications, magic links represent a net security improvement.

Magic Links vs Passkeys: What's the Difference?

Passkeys (WebAuthn) are the more modern passwordless option, using public-key cryptography and device biometrics. The comparison matters for teams choosing between them.

DimensionMagic LinksPasskeys
Requires email access to authenticateYes, every timeNo: uses device/biometric
Phishing resistanceMediumVery high: bound to origin URL
Works on new devicesYes: email accessible everywhereRequires sync or fallback setup
Implementation complexityLowHigher: WebAuthn API required
User familiarityHigh: everyone uses emailGrowing: newer concept for users
Recovery pathEmail is the recovery pathNeeds backup codes or recovery method

For most applications today, magic links are the pragmatic passwordless choice. Passkeys offer superior phishing resistance and are worth adding as an upgrade path: but magic links are simpler to implement, universally accessible, and already well-understood by users.

The Security Requirements a Magic Link Must Meet

OWASP's Forgot Password Cheat Sheet defines the security properties that any token-based authentication mechanism must satisfy. Applied to magic links:

  • Cryptographic randomness: The token must be generated using a CSPRNG, not Math.random() or any predictable source. Minimum 128 bits of entropy: typically a 32-byte hex or base64url string.
  • Hash before storing: The server stores the hash of the token, not the raw token. SHA-256 is sufficient because the token is already high-entropy and not user-chosen.
  • Short expiry window: Tokens must expire. 15 minutes is the OWASP recommendation. Longer windows increase the exposure window if the email is intercepted.
  • Single use enforced: The token must be invalidated immediately upon successful use. A token that can be reused is as dangerous as a password that never expires.
  • Rate limiting on requests: Limit how many magic links a given email address can request per hour to prevent email flooding abuse.
  • HTTPS only: The link must use HTTPS. Sending tokens over HTTP exposes them to interception.

How to Implement Magic Links in Node.js

You can implement magic links from scratch in Node.js, or use a library that handles the security requirements for you. The core implementation requires: a token generator, a storage mechanism (database), an email sender, and a verification endpoint.

The critical piece most implementations get wrong is token storage. Never store the raw token. Hash it first:

The token generation and verification flow in pseudocode: const token = crypto.randomBytes(32).toString('hex'); const hash = crypto.createHash('sha256').update(token).digest('hex');: store the hash, send the raw token in the email link, verify by hashing the incoming token and comparing to the stored hash.

OwlAuth handles all of these requirements automatically: CSPRNG token generation, SHA-256 hashing at rest, 15-minute expiry, and single-use enforcement: in a single sendMagicLink() call aligned with the OWASP Forgot Password Cheat Sheet.

Common Magic Link Mistakes to Avoid

  • Using Math.random() for token generation: predictable, not cryptographic. Always use crypto.randomBytes() in Node.js.
  • Storing the raw token in the database: if your database leaks, attackers get valid authentication tokens. Always store the hash.
  • No expiry or very long expiry: a magic link valid for 24 hours gives attackers a full day to use an intercepted link. 15 minutes is the standard.
  • Not enforcing single-use: if the token can be used multiple times, it functions like a persistent password that happens to live in an email.
  • Sending to unverified email addresses: verify that the email address belongs to an existing account before sending a link, or you become a spam relay.
  • No rate limiting: without limits, an attacker can flood any email address with magic link requests.

References

  1. 1OwlAuth: Node.js Authentication Library with Magic Links
  2. 2OWASP Authentication Cheat Sheet
  3. 3OWASP Forgot Password Cheat Sheet

Q&A Section

Yes: many successful products (Slack, Notion, Linear) use magic links as the primary or only login method. The key dependency is email reliability. If your users frequently can't access their email at login time, consider offering a password as a fallback option.
The attacker can use the link within its expiry window (typically 15 minutes) to authenticate. This is the core risk of email-based authentication. Mitigations include short expiry windows, sending login notifications to the user, and offering session alerts for logins from new devices.
No. bcrypt is designed for password hashing because passwords are low-entropy and user-chosen, requiring a deliberately slow algorithm to resist brute-force attacks. Magic link tokens are high-entropy random values: SHA-256 is sufficient and much faster. Using bcrypt for tokens just adds unnecessary latency.
Functionally, a password reset link and a magic link use the same cryptographic mechanism: a single-use, time-limited token sent to email. The difference is intent: a reset link is used once to set a new password, while a magic link is used as the ongoing authentication method, replacing passwords entirely.
Copied!