Understanding Magic Links
What are Magic Links?
Imagine you have a car repair shop. When a customer's car is ready, you want to notify them via SMS or email:
📱 Via SMS
Hi Sarah! Your Honda Civic is ready.
View details: https://app.link/l/xyz
📧 Via Email
Subject: Your Honda Civic is Ready!
Hi Sarah,
Great news! Your Honda Civic has been serviced and is ready for pickup.
https://app.link/l/xyz
When Sarah clicks the link (from either SMS or email), she sees ONLY her appointment details. No login required. No navigation. Just the info she needs.
Why are they called "magic"?
😞 Traditional auth flow:
- Click link
- See login page
- Try to remember password
- Click "Forgot password"
- Check email for reset link
- Finally see your content
✨ Magic link flow:
- Click link
- See your content
Security Requirements
But wait - if there's no login, how do we keep it secure?
1. Cryptographic Signature
The link contains a signature that proves we created it. Tampering with the link invalidates the signature.
2. Expiration
Links expire after 24 hours (or whatever you choose). Old links stop working automatically.
3. Stateless Validation
We don't store tokens in a database. Everything is encoded in the token itself.
🤔 Quick Check
What happens if someone changes the customer ID in the URL?
Block Methodology
What makes this a "block"?
A block is a piece of software that:
- ✓ Does ONE thing well
- ✓ Has clear inputs and outputs
- ✓ Works independently
- ✓ Is fully tested
- ✓ Has no side effects
Magic Link Generator Block:
✓ Does ONE thing: Generates and validates secure tokens
✓ Clear interface: generateLink(params) → SecureLink
✓ Independent: Doesn't call other blocks
✓ Tested: 21 comprehensive tests
✓ No side effects: Pure functions, no database
What this block does NOT do
Following the single responsibility principle:
- ✗ Send SMS - that's the SMS Sender block
- ✗ Render HTML - that's the Page Generator block
- ✗ Store data - that's the Context Store block
The hierarchy
Design Phase (Interfaces First)
Step 1: Define the inputs
Before writing ANY code, we design the interface. What data do we need to generate a magic link?
export interface LinkParams {
customerId: string; // Who is this for?
contextType: string; // What kind of content?
contextId: string; // Which specific item?
expiresIn: number; // How long is it valid?
}
Step 2: Define the outputs
What should generateLink() return?
export interface SecureLink {
url: string; // Full URL: https://app.link/l/xyz
token: string; // Just the token: xyz
expiresAt: number; // Unix timestamp
}
Step 3: Define validation output
When we validate a token, what do we need to know?
export interface ValidationResult {
customerId: string; // Extracted from token
contextType: string; // Extracted from token
contextId: string; // Extracted from token
expiresAt: number; // When it expires
isExpired: boolean; // Is it still valid?
}
Step 4: Design the class
Now we design the main class interface:
export class MagicLinkGenerator {
constructor(baseUrl: string, secret: string)
async generateLink(params: LinkParams): Promise<SecureLink>
async validateLink(token: string): Promise<ValidationResult | null>
}
🎉 Congratulations!
Badge Earned!
Magic Link Generator
You've completed the Magic Link Generator tutorial!
You now understand:
- ✓ What magic links are and why they're useful
- ✓ How to build blocks using TDD
- ✓ How cryptographic signing keeps links secure
- ✓ How to write comprehensive tests