No Passwords to Forget
Nothing to remember, nothing to write down, nothing to lose.
HomeStar uses passwordless magic link authentication instead of traditional passwords for favorites sync and account access.
A magic link is a single-use URL sent to your email that logs you in when clicked. No password to remember, no typing required.
Here’s how it works:
That’s it. No password creation, no “forgot password” flow, no security questions.
No Passwords to Forget
Nothing to remember, nothing to write down, nothing to lose.
More Secure
Magic links expire in 15 minutes and work only once—can’t be reused or stolen.
Faster Access
Click the link and you’re in—no typing passwords on mobile keyboards.
Cross-Device Ready
Check email on your phone, click the link, instantly synced.
Traditional passwords have significant security issues:
Magic links eliminate these vulnerabilities:
| Feature | Security Benefit |
|---|---|
| Time-limited | Links expire in 15 minutes, minimizing exposure window |
| Single-use | Once clicked, the link is invalidated—can’t be reused |
| Email verification | Proves you control the email address |
| No stored secrets | No password hashes to leak in a database breach |
| Unique tokens | Each link is cryptographically unique |
Traditional authentication flow:
Magic link flow:
Typing complex passwords on mobile keyboards is painful. Magic links eliminate this entirely—just tap the link in your email app.
Traditional flow: “Did I use my work email or personal email? Which password did I use?”
Magic link flow: “I’ll just use this email and click the link.”
When you request a magic link:
https://yoursite.com/auth/verify?token=abc123...When you click the link:
After authentication:
We use your email only for authentication and favorites sync. Specifically:
Our magic link emails don’t include tracking pixels or read receipts. We don’t know if you opened the email—only if you clicked the link.
We store only what’s necessary:
| Data | Purpose | Retention |
|---|---|---|
| Email address | Identify your account | Until you delete account |
| Magic link token | One-time authentication | 15 minutes then deleted |
| JWT token | Session authentication | 30 days or until sign out |
| Favorites list | Sync across devices | Until you delete favorites |
To prevent abuse, magic links are rate-limited:
If you exceed this, you’ll see a message: “Too many requests. Please wait 15 minutes.”
This prevents:
| Aspect | Passwords | Magic Links |
|---|---|---|
| Security | Weak if reused or simple | Strong cryptographic tokens |
| User friction | High (create, remember, reset) | Low (just click link) |
| Mobile UX | Poor (typing complex passwords) | Excellent (tap link) |
| Breach risk | High (password hashes leaked) | Low (no stored secrets) |
| Phishing risk | High (fake login pages) | Low (link contains auth) |
| Aspect | OAuth | Magic Links |
|---|---|---|
| Privacy | Shares data with third party | No third party involved |
| Dependency | Requires external account | Just need email |
| Complexity | Multiple redirects | Single email click |
| Trust | ”Why does this need my Google?" | "Just my email? Cool.” |
| Aspect | SMS Codes | Magic Links |
|---|---|---|
| Reliability | SMS can be delayed | Email is more reliable |
| Cost | SMS costs money | Email is free |
| Accessibility | Requires phone number | Works with any email |
| Security | SIM swapping attacks | Email account compromise only |
For developers integrating magic link auth:
// Request magic linkasync function requestMagicLink(email) { const response = await fetch('/auth/magic-link', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }) }); return response.json();}
// Verify magic link tokenasync function verifyToken(token) { const response = await fetch(`/auth/verify?token=${token}`); const data = await response.json();
if (data.jwt) { localStorage.setItem('idx_auth_token', data.jwt); localStorage.setItem('idx_auth_email', data.email); }
return data;}
// Check auth statefunction isAuthenticated() { const token = localStorage.getItem('idx_auth_token'); if (!token) return false;
// Decode JWT and check expiration const payload = JSON.parse(atob(token.split('.')[1])); return payload.exp > Date.now() / 1000;}We’re exploring additional passwordless options:
These will be optional additions—magic links will always be the primary method.