โ† Pattern library

Authentication

Magic Link Sign-in

Passwordless sign-in. User enters email, gets a one-time link, clicks it, and is signed in. No password to remember.

๐ŸŒฑ

When to use this

When you want minimal friction signup, especially for low-security apps or B2B prospect tools.

authloginpasswordlessemailmagic-link
โœจ Built using these library patterns:
magic-link

What I assumed

I made these guesses to fill gaps. Let me know if any are wrong.

    Flow diagram

    Step-by-step recipe

    Copy this and paste into Cursor, Claude Code, or v0.

    PATTERN: Magic Link Sign-in
    INPUT: email
    OUTPUT: session_token | error_message
    
    STEPS:
      1. User enters email on sign-in form
      2. Validate email format on client
      3. Generate one-time signed token (15-min expiry)
      4. Store token hash + email + expiry in DB
      5. Send email with link containing token
      6. Show "Check your email" confirmation screen
      7. User clicks link in email
      8. Server validates token: not expired, not used, hash matches
      9. IF invalid โ†’ show "This link expired or was already used. Send new one?"
      10. Mark token as used (single-use)
      11. Create session, set HttpOnly cookie
      12. Redirect to destination
    
    ERROR_HANDLING:
      - Email service down โ†’ queue retry, show "We had trouble sending โ€” try again"
      - User requests multiple links โ†’ invalidate previous, send new one
      - Link clicked twice โ†’ second click shows "Already used"
      - Token tampered โ†’ reject silently, log security event
    
    EXTENSION_POINTS:
      - First-time signup detection (composable_with: ["email-verification"])
      - Link from existing OAuth account (composable_with: ["account-linking"])
      - Add password later for power users (composable_with: ["email-login"])
    

    States โ€” how things change

    StateDescriptionTransitions
    Awaiting email inputUser on sign-in form
    • Email submittedโ†’Link sent
    Link sentEmail dispatched, waiting for click
    • Link clickedโ†’Validating token
    • Expiredโ†’Awaiting email input
    Validating tokenServer checking token validity
    • Validโ†’Signed in
    • Invalidโ†’Awaiting email input
    Signed inActive sessionterminal

    Easy-to-miss situations

    The kinds of edge cases that break demos.

    • What if the email goes to spam?

      high

      User waits, gets confused, gives up.

      Suggested handling: Use Resend/Postmark with verified DKIM/SPF. Tell user "Didn't see it? Check spam, or resend in 30s."

    • What if a typo in email creates an account for the wrong person?

      high

      Magic link goes to a stranger; if they click it, they're in.

      Suggested handling: Show typed email back BEFORE sending: "We'll send a link to alice@exmaple.com โ€” correct?". Add 5-second cancel window.

    • What if the user opens link on a different device?

      medium

      They submitted email on phone, but tap link on tablet email app.

      Suggested handling: Allow it (most common case). Don't bind token to device fingerprint. Show "Welcome on Tablet" if device differs from request.

    • What if the user requests 5 magic links rapidly?

      medium

      Spam your email service, confuse user with multiple emails.

      Suggested handling: Rate-limit per email (1 per 30s). Invalidate previous tokens when issuing new โ€” only latest works. Show "Already sent โ€” check your inbox" on rapid resend.

    • What if attacker intercepts email contents?

      medium

      Magic link in email body โ€” if email is unencrypted in transit/storage, link is exposed.

      Suggested handling: Short token expiry (15 min). Single-use enforcement. For high-security apps, require email + 2FA challenge instead.

    Composes well with

    Combine these patterns when you need a richer flow.

    Build a flow starting from this pattern โ†’