Magic Login Setup Guide
Magic Link is a passwordless authentication method that allows users to log in by clicking a secure email link instead of entering a password. Mindful Auth’s magic link authentication provides enterprise-grade security through a multi-layered defense system. When 2FA is enabled, users must pass through four distinct security layers before gaining access.
Without 2FA (Two Layers)
- Magic Link Token - Unique, time-limited token sent to verified email address
- Turnstile Bot Protection - Cloudflare Turnstile validates human interaction on verification page
With 2FA Enabled (Four Layers)
- Magic Link Token - Unique, time-limited token sent to verified email address
- First Turnstile Validation - Bot protection validates human on initial page visit
- 2FA Code - TOTP code from authenticator app (separate device)
- Second Turnstile Validation - Fresh bot protection token validates human during 2FA submission
Magic Link provides two workflows:
Section titled “Magic Link provides two workflows:”- Registration — New user creates account and verifies email via magic link
- Login — Existing user requests magic link to authenticate without password
Both flows use one-time tokens that expire after 15 minutes (login) or 24 hours (registration verification).
Registration Flow
Section titled “Registration Flow”Step 1: User Submits Registration Form
Section titled “Step 1: User Submits Registration Form”Endpoint: POST /auth/register-magic-link
Request:
{ "email": "user@example.com", "name": "John Doe", "cf-turnstile-response": "<turnstile-token>"}Security Checks:
- ✅ Turnstile bot protection (required)
- ✅ IP-based registration rate limit (5 registrations/hour per IP)
- ✅ Email velocity tracking (3 attempts/hour per email, 5+ IPs = harassment detected)
Step 2: Account Created with Pending Verification
Section titled “Step 2: Account Created with Pending Verification”If all checks pass:
- New user record created in backend with
authentication_status: "Email Verification Pending" authentication_type: ["Magic Link"]set (user can add password later)_2fa_status: "Disabled"(user can enable 2FA after email verification)- No password set (passwordless account)
Response:
{ "success": true, "recordid": "123456789", "message": "Account created. Please check your email to verify your account."}Step 3: Verification Email Sent
Section titled “Step 3: Verification Email Sent”- Verification token (32-byte, base64-encoded) generated
- Token stored in Cloudflare KV with 24-hour expiration
- Email sent via
emailVerificationWebhook(tenant-configured automation) - Email contains verification link:
https://portal.example.com/email-verified/{recordId}/{token}
Webhook Payload:
{ "event_type": "magic_login", "recordid": 123456789, "email": "email@example.com", "name": "John Doe", "verificationLink": "https://your.domain.com/email-verified/record_id/verificationToken"}Step 4: User Clicks Verification Link
Section titled “Step 4: User Clicks Verification Link”Endpoint: POST /auth/verify-email
Request:
{ "recordId": "123456789", "token": "abc123..."}Validation:
- Token must match Cloudflare KV stored token (one-time use)
- Token must not be expired (24-hour window)
On Success:
authentication_statusset to"Unlocked"- Token deleted from Cloudflare KV (can’t be reused)
- User can now log in
Login Flow
Section titled “Login Flow”Step 1: User Requests Magic Link
Section titled “Step 1: User Requests Magic Link”Endpoint: POST /auth/request-magic-link
Request:
{ "email": "user@example.com", "cf-turnstile-response": "<turnstile-token>"}Security Checks:
- ✅ Turnstile bot protection (required)
- ✅ IP-based rate limit (10 requests/hour per IP)
- ✅ Email velocity tracking (5+ IPs in 1 hour = harassment detected)
- ✅ Account status validation:
- Account must not be
Locked - Email must be verified (
authentication_status != "Email Verification Pending")
- Account must not be
Step 2: Conditions for Sending Magic Link
Section titled “Step 2: Conditions for Sending Magic Link”| Condition | Result |
|---|---|
| Account not found | Generic success (email enumeration protection) |
| Account locked | Generic success (don’t reveal locked status) |
| Email unverified | Explicit error: “Please verify your email first” |
| All checks pass | Magic link email sent |
Why generic responses? Prevents attackers from discovering which emails are registered.
Step 3: Magic Link Email Sent
Section titled “Step 3: Magic Link Email Sent”- Magic link token (32-byte, base64-encoded) generated
- Token stored in Cloudflare KV with 15-minute expiration (short window for security)
- Email sent via
magicLoginWebhook(tenant-configured automation) - Email contains login link:
https://portal.example.com/verify-magic-link/{recordId}/{token}
Webhook Payload:
{ "recordid": "123456789", "email": "user@example.com", "name": "John Doe", "magicLoginLink": "https://portal.example.com/verify-magic-link/123456789/xyz789..."}Step 4: User Verifies Magic Link
Section titled “Step 4: User Verifies Magic Link”Endpoint: POST /auth/verify-magic-link/{recordId}/{token}
Request:
{ "cf-turnstile-response": "<turnstile-token>", "twoFACode": "123456" // Optional, only if 2FA enabled}Validation:
- ✅ Turnstile bot protection (required)
- ✅ Magic link token must match Cloudflare KV (one-time use)
- ✅ Token must not be expired (15-minute window)
- ✅ Account must not be locked
- ✅ If 2FA enabled: require and validate 2FA code
Step 5a: 2FA Required (if enabled)
Section titled “Step 5a: 2FA Required (if enabled)”If user has 2FA enabled but didn’t provide code:
Response (200 OK):
{ "success": false, "requires2FA": true, "message": "2FA code is required."}Frontend re-prompts for 2FA code and calls endpoint again with twoFACode.
Step 5b: Login Successful
Section titled “Step 5b: Login Successful”- Magic link token deleted from Cloudflare KV (one-time use)
- Session created with user’s recordId
- Session cookie set:
session_id={sessionId}; HttpOnly; Secure; SameSite=Lax - Session TTL determined by
sessionTier(configurable: 15-mins to 30-days)
Response (200 OK):
{ "success": true, "message": "Login successful!", "redirect": "/dashboard" // Determined by loginSuccessRedirect config}Set-Cookie Header:
session_id=sess_abc123...; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600Token Security
Section titled “Token Security”One-Time Use Tokens
Section titled “One-Time Use Tokens”- Tokens are deleted immediately after use (Cloudflare KV.delete)
- Cannot be reused even within the expiration window
- If user clicks link twice, second click fails with “Invalid or expired magic link”
Token Format
Section titled “Token Format”- Size: 32 random bytes (256 bits of entropy)
- Encoding: Base64 URL-safe (+ replaced with -, / replaced with _, = removed)
- Example:
abc123-_XYZ789(no +/= characters)
Token Storage
Section titled “Token Storage”- Cloudflare KV Key Format:
- Login:
magic_link:{hostname}:{recordId} - Registration:
email_verify:{hostname}:{recordId}
- Login:
- TTL:
- Magic link (login): 15 minutes
- Verification token (registration): 24 hours
- No plaintext in logs — only token existence is logged, never the actual token
Rate Limiting & Abuse Prevention
Section titled “Rate Limiting & Abuse Prevention”Registration Velocity Limits
Section titled “Registration Velocity Limits”| Limit | Scope | Window | Block Action |
|---|---|---|---|
| 5 registrations | Single IP | 1 hour | 429 Too Many Requests |
| 3 attempts | Single email | 1 hour | 429 Too Many Requests |
| 5+ IPs | Single email | 1 hour | Log warning (allowed but flagged) |
Magic Link Request Limits
Section titled “Magic Link Request Limits”| Limit | Scope | Window | Block Action |
|---|---|---|---|
| 10 requests | Single IP | 1 hour | 429 Too Many Requests |
| 5+ IPs | Single email | 1 hour | 429 Too Many Requests |
| 1 per email | Per email | 3 minutes | 429 Too Many Requests |
Why Multiple Limits?
Section titled “Why Multiple Limits?”- IP-based: Prevents single attacker from spamming many emails
- Email-based: Detects distributed attacks (many IPs hammering one email)
- Cooldown: Prevents immediate retry of same email
Adding Magic Link to Your Tenant
Section titled “Adding Magic Link to Your Tenant”1. Configure Webhook URLs
Section titled “1. Configure Webhook URLs”During tenant onboarding, provide:
{ "magicLoginWebhook": "https://your-automation.com/send-magic-link", "emailVerificationWebhook": "https://your-automation.com/verify-email"}These are webhook URLs pointing to your email automation service (Tape automation, Make, Zapier, n8n, etc.).
2. Create Email Templates
Section titled “2. Create Email Templates”Your automation should:
- Accept
recordid,email,name,magicLoginLink(login flow) - Accept
recordid,verificationLink(registration flow) - Send branded emails with secure links
- Never log or display tokens in plaintext
3. Frontend Setup
Section titled “3. Frontend Setup”- Add Turnstile widget to registration & magic link request forms
- Create
/email-verified/{recordId}/{token}page to verify email - Create
/verify-magic-link/{recordId}/{token}page to verify login - Handle
requires2FA: trueresponse by prompting for 2FA code
Audit Events
Section titled “Audit Events”Magic Link generates comprehensive audit logs. See Audit Logs Guide for details.
Comparison with Password Authentication
Section titled “Comparison with Password Authentication”| Feature | Magic Link | Password |
|---|---|---|
| Credentials required | None (email only) | Password + email |
| Reset flow | Email verification | Password reset via email |
| Phishing risk | Low (token expires in 15 min) | Medium (password reuse) |
| Usability | High (click link) | Medium (remember password) |
| 2FA capable | Yes (optional) | Yes (optional) |
| Account recovery | Password reset available | Password reset only |
| Session TTL | Configurable (15 min - 30 days) | Configurable (15 min - 30 days) |
Attack Resistance
Section titled “Attack Resistance”| Attack Vector | Without 2FA | With 2FA |
|---|---|---|
| Email compromise | ❌ Vulnerable | ✅ Blocked by 2FA |
| Automated bots | ✅ Blocked by Turnstile | ✅ Blocked by dual Turnstile |
| Phishing/social engineering | ❌ Vulnerable | ⚠️ Mitigated (requires TOTP) |
| Token replay | ✅ Blocked (single-use) | ✅ Blocked (single-use) |
| Brute force | ✅ Blocked (velocity limits) | ✅ Blocked (velocity + 2FA) |
Comparison to Traditional Magic Links
Section titled “Comparison to Traditional Magic Links”Most magic link implementations provide only one layer (email token). Mindful Auth provides:
- 2x security layers (minimum) - Magic link + Turnstile
- 4x security layers (with 2FA) - Magic link + Turnstile + 2FA + Turnstile
This exceeds the security of traditional password + 2FA systems, while providing better user experience (no password to remember/manage).
Common Issues & Solutions
Section titled “Common Issues & Solutions”| Issue | Cause | Solution |
|---|---|---|
| User gets “Invalid or expired link” | Token expired after 15 min or already used | Request new magic link (3-minute cooldown) |
| “You’ve requested too many links” | Rate limit triggered | Wait 3 minutes or try different email |
| ”Bot protection validation failed” | Turnstile widget not passed or expired | Refresh page and try again |
| Email never arrives | Webhook not configured or automation failed | Check webhook URL in tenant config |
| User registers but can’t log in | Email not verified yet | Click verification link in email first |
| ”Account has been locked” | Admin locked account | Contact support to unlock |