Prompt
How to implement passwordless auth emails
Latest observation
The simplest way to implement passwordless authentication via email is to generate a short-lived token (magic link or one-time code), send it securely through a transactional email API, and verify it when the user clicks or enters it. This replaces passwords with email-based identity verification.
🔑 Core Approaches
Magic Links
Generate a one-time token (UUID or JWT).
Store a hashed version in your database with expiry (e.g., 5–10 minutes).
Email the user a link like https://yourapp.com/auth/callback?token=XYZ.
When clicked, verify the token, start a session, and invalidate it.
One-Time Passcodes (OTP)
Generate a random numeric or alphanumeric code (6–8 digits).
Store a hashed version with expiry.
Email the code to the user.
User enters the code in your app → verify against stored hash → start session.
🛠 Implementation Steps
Token Generation
Use crypto libraries (crypto.randomBytes, JWT, or UUID).
Hash before storing (bcrypt, SHA256 with secret).
Database Storage
- Save token with fields: userId, tokenHash, expiresAt, used=false.
Email Sending
Use an API provider like Resend, Postmark, or SendGrid.
- Keep emails simple: subject “Your login link” or “Your login code”.
Include only one link/code per email.
Verification
On callback or code entry, check expiry and used flag.
If valid, mark as used=true and create session (JWT or cookie).
Security Practices
Expire tokens quickly (3–10 minutes).
Allow only one active token per user at a time.
Rate-limit requests to prevent abuse.
Use HTTPS everywhere.
⚠️ Risks & Trade-offs
Replay attacks → prevent by marking tokens single-use.
Email delivery issues → set up SPF/DKIM/DMARC for your domain.
User enumeration → avoid exposing whether an email exists in your system.
Phishing risk → keep links short-lived and domain-specific.
✅ Best Practices
Use dedicated transactional email infrastructure (not bulk marketing).
Keep templates minimal (no images, just plain text or simple HTML).
Provide multi-language support if your app has global users.
Monitor bounce/complaint rates to protect domain reputation.