← Recipes

阅读中文版本

Implement Secure Magic-Link Login

Issue a single-use, short-lived, hashed token in an email link, verify it atomically, and bind it to the requesting context to prevent reuse.

~40 minauthenticationpasswordlesssecurity

Task

Add passwordless email login with single-use tokens that cannot be replayed.

When to use this

A magic-link token is stored in plaintext, never expires, and can be used repeatedly, so a leaked email grants permanent access.

Prerequisites

  • An email delivery service
  • A store for token hashes and expiry

Steps

1. Generate a high-entropy token, store only its hash with an expiry.

Expected output: A database leak does not reveal usable tokens.

2. Send a link containing the token over HTTPS with a short lifetime.

Expected output: The link is useless after the window.

3. On verification, atomically consume the token so it cannot be reused.

Expected output: Replay attempts fail.

4. Bind the token to a pending session or user and issue the real session only after success.

curl "https://app.example.com/auth/verify?token=$TOKEN"

Expected output: Stolen links cannot be used elsewhere without context.

Troubleshooting

Problem

Link scanners consume the token

Solution

Some mail scanners follow links; consider a confirm button or a scanner-safe landing page.

Problem

Token reused

Solution

Consume atomically with a conditional update and reject consumed or expired tokens.

Limitations

  • Magic links depend on email deliverability and can be delayed; they are not ideal for time-critical access.
  • They shift the security boundary to the email account, so account takeover of email still compromises access.

Context

Add passwordless email login with single-use tokens that cannot be replayed. A magic-link token is stored in plaintext, never expires, and can be used repeatedly, so a leaked email grants permanent access.

Steps

  1. Generate a high-entropy token, store only its hash with an expiry. Expected: A database leak does not reveal usable tokens.
  2. Send a link containing the token over HTTPS with a short lifetime. Expected: The link is useless after the window.
  3. On verification, atomically consume the token so it cannot be reused. Expected: Replay attempts fail.
  4. Bind the token to a pending session or user and issue the real session only after success. Expected: Stolen links cannot be used elsewhere without context.
const token = base64url(crypto.randomBytes(32));
await db.insert({ hash: sha256(token), expiresAt: now + 10 * 60_000 });
// verify: atomic single use
await db.consume(hash, { now });

Verify

  • A database leak does not reveal usable tokens.
  • The link is useless after the window.
  • Replay attempts fail.
  • Stolen links cannot be used elsewhere without context.

Limits

  • Magic links depend on email deliverability and can be delayed; they are not ideal for time-critical access.
  • They shift the security boundary to the email account, so account takeover of email still compromises access.