Auth: Add 2FA requirement to magic link login flow

Status Closed — not planned
Maintainer reply None cached
Activity 3 comments · opened Nov 26, 2025 · closed Jan 26, 2026

Summary

Add 2FA (TOTP) verification requirement to magic link login when users have mfaPreference.twoFA enabled, matching the security of password login.

Current Behavior

  • Password login (post-login-password.ts) checks mfaPreference.twoFA and requires TOTP before issuing JWT
  • Magic link login (post-verify-login.ts, post-verify-login-worker.ts) skips 2FA entirely and issues JWT immediately

Proposed Implementation

Use the Intermediate Session Token (IST) pattern (industry standard used by Stytch, Auth0):

Flow

  1. User clicks magic link
  2. POST /auth/v1/login/verify { magicToken }
  • If 2FA enabled: returns { intermediateToken, state: ONE, mfaRequired: true }
  • If no 2FA: returns { accessToken, state: TWO } (current behavior)
  1. POST /auth/v1/login/verify { intermediateToken, token: "123456" }
  • Validates IST + TOTP → returns { accessToken, state: TWO }

Why IST Pattern

  • Magic link stays one-time use (consumed immediately)
  • IST is short-lived (10 minutes) reducing attack window
  • Clean separation of authentication stages
  • Industry standard approach

Files to Modify

  • services/auth/handlers/post-verify-login.ts - Add 2FA check for integrators
  • services/auth/handlers/post-verify-login-worker.ts - Add 2FA check for workers
  • lib/schemas/models/session.ts - Add IST creation/validation functions
  • services/auth/schema/request/ - Update request schemas to accept intermediateToken + token

Acceptance Criteria

  • [ ] Magic link login requires 2FA when mfaPreference.twoFA is enabled
  • [ ] Intermediate tokens expire after 10 minutes
  • [ ] Intermediate tokens are one-time use
  • [ ] Existing flow unchanged when 2FA not enabled
  • [ ] Works for both integrators and workers/admins

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗