Magic Link Authentication
Passwordless authentication via email link for simplified login experience.
Overview
Magic links provide a passwordless login experience:
- User enters email
- Receives email with login link
- Clicking link authenticates user
No password required - authentication is verified via email ownership.
Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/api/auth/magic-link/request |
Request magic link |
GET |
/api/auth/magic-link/verify |
Verify and authenticate |
POST /api/auth/magic-link/request
Request a magic link email.
Synopsis
| Property | Value |
|---|---|
| Authentication | Public |
| Rate Limit | 5/minute |
| Token Lifetime | 15 minutes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email |
string |
Yes | User’s email address |
org_slug |
string |
No | Organization for branded emails |
Example Request
curl -X POST https://sso.example.com/api/auth/magic-link/request \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"org_slug": "acme-corp"
}'
Response (200 OK)
{
"message": "If the email exists, a magic link has been sent."
}
[!NOTE] Always returns success to prevent email enumeration attacks.
Errors
| Status | Condition |
|---|---|
400 |
Invalid email format |
429 |
Rate limit exceeded |
GET /api/auth/magic-link/verify
Verify magic link token and authenticate user.
Synopsis
| Property | Value |
|---|---|
| Authentication | Public |
| Risk Assessment | Yes |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string |
Yes | Magic link token from email |
redirect_uri |
string |
No | Redirect URL after auth |
Example Request
curl -X GET "https://sso.example.com/api/auth/magic-link/verify?token=magic-token-uuid"
Response - Success (200 OK)
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "550e8400-e29b-41d4-a716-446655440000",
"expires_in": 900
}
Response - High Risk (200 OK)
{
"requires_mfa": true,
"preauth_token": "eyJhbGciOiJSUzI1NiIs...",
"message": "Additional verification required"
}
When requires_mfa: true, continue with MFA verification.
Errors
| Status | Condition |
|---|---|
400 |
Invalid or expired magic link |
400 |
User not found (must register first) |
403 |
Blocked by risk engine |
Magic Link Flow
sequenceDiagram
participant User
participant Client
participant AuthOS
participant Email
User->>Client: Enter email
Client->>AuthOS: POST /api/auth/magic-link/request
AuthOS->>Email: Send magic link
AuthOS-->>Client: {message: "..."}
Email->>User: Magic link email
User->>AuthOS: Click link (GET /verify?token=...)
AuthOS->>AuthOS: Risk assessment
alt Low Risk
AuthOS-->>Client: {access_token, refresh_token}
else High Risk
AuthOS-->>Client: {requires_mfa: true}
end
Security Features
| Feature | Description |
|---|---|
| One-Time Use | Token deleted after verification |
| Short Expiry | 15-minute validity |
| Risk Assessment | Evaluates IP, location, device |
| Device Trust | Establishes 90-day trusted device cookie |
| Rate Limiting | 5 requests per minute |
Device Trust
On successful low-risk authentication, a device trust cookie is set:
Set-Cookie: device_token={signed-token}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=7776000
Trusted devices may bypass MFA for subsequent logins.