Passwordless authentication flow using email magic links with time-limited tokens and security validation.
flowchart TD
Start([User visits /login]) --> EnterEmail[User enters email address]
EnterEmail --> ValidateFormat{Email format valid?}
ValidateFormat -->|No| ShowError1[Show: Invalid email format]
ShowError1 --> EnterEmail
ValidateFormat -->|Yes| CheckRateLimit{Rate limit check<br/>5 attempts/15min per IP}
CheckRateLimit -->|Exceeded| ShowError2[Show: Too many attempts<br/>Try again in 15 minutes]
ShowError2 --> End1([End])
CheckRateLimit -->|OK| CheckDevMode{Development mode?}
CheckDevMode -->|Yes| CreateSession1[Create session cookie]
CreateSession1 --> RedirectDash1[Redirect to /admin]
RedirectDash1 --> End2([End - Dev Auto-Login])
CheckDevMode -->|No - Production| CheckDomain{Email domain<br/>authorized?}
CheckDomain -->|No| ShowError3[Show: Email not authorized<br/>to access portal]
ShowError3 --> End3([End])
CheckDomain -->|Yes| CheckAutoLogin{Email in<br/>AUTO_LOGIN_EMAILS?}
CheckAutoLogin -->|Yes| CreateSession2[Create session cookie<br/>7 day expiry]
CreateSession2 --> RedirectDash2[Redirect to /admin]
RedirectDash2 --> End4([End - Auto-Login])
CheckAutoLogin -->|No| GenerateToken[Generate magic token<br/>Base64 encoded JSON]
GenerateToken --> TokenData[Token contains:<br/>• email<br/>• expiry: now + 15 min]
TokenData --> BuildLink[Build magic link:<br/>origin/verify?token=token]
BuildLink --> SendEmail[Send email via<br/>Google Workspace SMTP]
SendEmail --> EmailCheck{Email sent<br/>successfully?}
EmailCheck -->|No| ShowError4[Show: Failed to send email<br/>Please try again]
ShowError4 --> End5([End])
EmailCheck -->|Yes| ShowSuccess[Show: Check your email<br/>Link expires in 15 minutes]
ShowSuccess --> UserWaits[User checks email]
UserWaits --> UserClick[User clicks magic link]
UserClick --> VerifyPage[Navigate to /verify?token=...]
VerifyPage --> ExtractToken[Extract token from URL]
ExtractToken --> DecodeToken{Token valid<br/>Base64?}
DecodeToken -->|No| ShowError5[Show: Invalid or expired link]
ShowError5 --> End6([End])
DecodeToken -->|Yes| ParseData[Parse JSON data]
ParseData --> CheckExpiry{Token expired?<br/>now > exp}
CheckExpiry -->|Yes| ShowError6[Show: Link expired<br/>Please request a new one]
ShowError6 --> End7([End])
CheckExpiry -->|No| VerifyEmail{Email matches<br/>token email?}
VerifyEmail -->|No| ShowError7[Show: Invalid token]
ShowError7 --> End8([End])
VerifyEmail -->|Yes| CreateSession3[Create session cookie<br/>HttpOnly, SameSite=strict<br/>7 day expiry]
CreateSession3 --> ClearToken[Clear token from memory]
ClearToken --> RedirectDash3[Redirect to /admin]
RedirectDash3 --> End9([Authenticated Session])
style Start fill:#e3f2fd
style End1 fill:#ffebee
style End2 fill:#e8f5e9
style End3 fill:#ffebee
style End4 fill:#e8f5e9
style End5 fill:#ffebee
style End6 fill:#ffebee
style End7 fill:#ffebee
style End8 fill:#ffebee
style End9 fill:#e8f5e9
style CreateSession1 fill:#fff9c4
style CreateSession2 fill:#fff9c4
style CreateSession3 fill:#fff9c4
style SendEmail fill:#e1f5fe
style GenerateToken fill:#f3e5f5The magic link authentication system provides passwordless login through email verification. Users receive a time-limited link that authenticates them without requiring password entry.
File: src/routes/login/+page.server.ts
Function: generateMagicToken()
Service: src/lib/services/email.service.server.ts
File: src/routes/verify/+page.server.ts
File: src/routes/quote/config.ts