Favorites Architecture
The Favorites system enables cross-device synchronization using lightweight magic link authentication, providing seamless favorites management without requiring full user registration.
Authentication Flow
Section titled “Authentication Flow”The favorites authentication flow is designed for minimal friction while maintaining security:
1. POST /api/v1/favorites/magic-link → Magic link email sent2. User clicks email link → Browser opens /auth/verify/{token}3. GET /api/v1/favorites/verify/{token} → Returns auth_token + favorites4. POST /api/v1/favorites/sync → Syncs localStorage favorites5. Future requests use Authorization: Bearer {auth_token}Why Magic Links?
Section titled “Why Magic Links?”Traditional registration creates friction for users who simply want to save favorites. Magic links provide:
- No password management — Users don’t need to remember credentials
- Email verification built-in — Email ownership is proven automatically
- Quick cross-device sync — Send link to any device to sync favorites
- Low security risk — Tokens only grant access to favorites, nothing else
Token Lifecycle
Section titled “Token Lifecycle”Magic Link Token:
- Expires after 15 minutes
- Can only be used once
- Links anonymous session to client account if session ID provided
- Generates an auth token upon successful verification
Auth Token (JWT):
- Valid for 90 days from issue
- Can be used repeatedly for favorites operations
- Scoped exclusively to favorites endpoints
- Cannot access admin, agent, or other protected resources
Security Design
Section titled “Security Design”Multi-Layered Protection
Section titled “Multi-Layered Protection”- Token Expiry — Magic links expire in 15 minutes to prevent stale link abuse
- Single Use — Each magic link can only be verified once
- Rate Limiting — Maximum 3 pending links per email per 15 minutes prevents spam
- Signed JWTs — Auth tokens are HMAC-signed with server secret
- Scoped Access — Favorites tokens explicitly cannot access other API resources
Rate Limiting Strategy
Section titled “Rate Limiting Strategy”The system tracks pending magic links per email address within 15-minute windows:
- First request — Link sent immediately
- Second request — Link sent (warning about existing links)
- Third request — Link sent (final warning)
- Fourth request — Rejected with 429 status
This prevents:
- Email spam abuse
- Accidental multiple link generation
- Denial-of-service attacks via email endpoints
Session Linking
Section titled “Session Linking”When requesting a magic link, clients can provide an X-Session-ID header. Upon token verification:
- Server looks up any existing anonymous session
- Merges anonymous favorites into the verified client account
- Associates session with client for future requests
This enables seamless transition from anonymous browsing to authenticated favorites sync.
Data Models
Section titled “Data Models”MagicLink Table
Section titled “MagicLink Table”Stores magic link requests and tracks usage:
| Column | Purpose |
|---|---|
token | Unique secure token (cryptographically random) |
email | Recipient email address |
session_id | Optional session to link on verification |
expires_at | Automatic cleanup after expiration |
used_at | Prevents reuse attacks |
client_id | Set on verification, links to Client record |
ClientFavorite Table
Section titled “ClientFavorite Table”Stores synced favorites with deduplication:
| Column | Purpose |
|---|---|
client_id | Owner of the favorite |
listing_id | MLS listing identifier |
created_at | When favorite was added |
Unique constraint on (client_id, listing_id) prevents duplicate favorites.
Sync Strategy: Union Merge
Section titled “Sync Strategy: Union Merge”The favorites sync uses a union merge strategy:
Server favorites: [A, B, C]Client favorites: [C, D, E]After sync: [A, B, C, D, E]Why Union Merge?
Section titled “Why Union Merge?”Prevents data loss:
- User favorites on phone don’t disappear when syncing from desktop
- No “last write wins” conflicts that lose data
- Favorites are only ever added during sync, never removed
Explicit deletion:
- Only
DELETE /api/v1/favorites/{listing_id}removes favorites - User must intentionally remove items
- Accidental syncs won’t lose data
Trade-offs
Section titled “Trade-offs”Pros:
- Simple and predictable behavior
- No lost favorites across devices
- Supports offline-first patterns
Cons:
- Deleted favorites on one device won’t sync deletion to others
- Requires explicit unfavorite action per device
- No “tombstone” markers for deletions
For most users, the safety of never losing favorites outweighs the inconvenience of manually unfavoriting on multiple devices.
JWT Token Structure
Section titled “JWT Token Structure”The auth token is a signed JWT with minimal claims:
{ "client_id": 123, "brokerage_id": 1, "email": "user@example.com", "exp": 1735689600, "iat": 1727913600, "type": "favorites_auth"}Claim Purposes
Section titled “Claim Purposes”| Claim | Purpose |
|---|---|
client_id | Identifies the client record for favorites lookup |
brokerage_id | Multi-tenant isolation (ensures correct data partition) |
email | Verified email for user display |
exp | Automatic token invalidation after 90 days |
type | Explicit scope marker (favorites_auth only) |
The type claim is checked on every favorites endpoint to prevent token reuse for unauthorized operations.
Related
Section titled “Related”- Favorites API Reference — Endpoint specifications
- Integrating Favorites in Frontend — Implementation guide