Files
triqura-ecd/docs/design/AUTH_SETUP.md
2025-11-23 10:13:00 +01:00

417 lines
9.7 KiB
Markdown

# 🔐 Authentication Setup Guide
**Project:** AI Speedrun - Mini-ECD Prototype
**Epic:** E2 - Database & Auth
**Story:** E2.S3 - Demo auth flow
**Last Updated:** 2024-11-15
---
## Overview
This document describes the authentication implementation for the EPD prototype, including magic link login and demo user accounts.
---
## Authentication Methods
### 1. Magic Link (Primary Method)
Users can sign in using email-only authentication:
1. User enters email on `/login`
2. Supabase sends magic link to email
3. User clicks link → auto-logged in
4. **New users:** Account is automatically created on first magic link request
**Benefits:**
- No password to remember
- More secure than traditional passwords
- Better UX for demo environment
- Auto-creates accounts (no separate signup flow needed)
---
### 2. Demo Accounts (For Presentations)
Pre-configured demo accounts for public demos and presentations:
| Email | Password | Access Level | Purpose |
|-------|----------|--------------|---------|
| demo@mini-ecd.demo | Demo2024! | interactive | Main demo account - full CRUD |
| readonly@mini-ecd.demo | Demo2024! | read_only | View-only for public demos |
| presenter@mini-ecd.demo | Demo2024! | presenter | Live presentations |
**Access Levels:**
- `read_only`: Can view all data, cannot create/edit/delete
- `interactive`: Full CRUD access to all features
- `presenter`: Full access + special presenter features (future)
---
## Setup Instructions
### 1. Environment Variables
Ensure these are set in your `.env.local`:
```bash
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://dqugbrpwtisgyxscpefg.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
# Service role key (for admin operations)
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
```
### 2. Create Demo Users
Run the seed script to create demo user accounts:
```bash
# Make sure you have tsx installed
pnpm add -D tsx
# Run the seed script
tsx scripts/seed-demo-users.ts
```
**Expected output:**
```
🌱 Starting demo user seed...
Creating user: demo@mini-ecd.demo...
✅ Created auth user: xxx-xxx-xxx
✅ Created demo_users entry
✨ demo@mini-ecd.demo ready!
Creating user: readonly@mini-ecd.demo...
✅ Created auth user: xxx-xxx-xxx
✅ Created demo_users entry
✨ readonly@mini-ecd.demo ready!
Creating user: presenter@mini-ecd.demo...
✅ Created auth user: xxx-xxx-xxx
✅ Created demo_users entry
✨ presenter@mini-ecd.demo ready!
✅ Demo user seed complete!
```
### 3. Configure Supabase Auth Settings
Go to Supabase Dashboard → Authentication → Settings:
#### Email Templates
Customize the magic link email template:
**Subject:** "Login to Mini-ECD"
**Body:**
```html
<h2>Je magic link is klaar!</h2>
<p>Klik op de knop hieronder om in te loggen bij Mini-ECD:</p>
<p><a href="{{ .ConfirmationURL }}">Login naar EPD</a></p>
<p>Of kopieer deze link naar je browser:</p>
<p>{{ .ConfirmationURL }}</p>
<p><small>Deze link is 1 uur geldig.</small></p>
```
#### Redirect URLs
Add these redirect URLs under "Redirect URLs":
```
http://localhost:3000/auth/callback
https://yourdomain.com/auth/callback
```
#### Email Auth Settings
- ✅ Enable Email provider
- ✅ Confirm email: OFF (for demo convenience)
- ✅ Secure email change: ON
- ⏱️ Rate limits: Default (4 emails per hour)
---
## File Structure
```
app/
login/
page.tsx # Login UI (magic link + demo login)
auth/
callback/
route.ts # Handles magic link callback
logout/
route.ts # Logout endpoint
lib/
auth/
client.ts # Client-side auth helpers
server.ts # Server-side auth helpers
database.types.ts # Generated Supabase types
middleware.ts # Route protection
scripts/
seed-demo-users.ts # Demo user creation script
```
---
## Usage Examples
### Client-Side (React Components)
```typescript
import {
loginWithMagicLink,
loginWithPassword,
logout,
getUser,
isDemoUser
} from '@/lib/auth/client'
// Magic link login
async function handleMagicLink(email: string) {
const result = await loginWithMagicLink(email)
console.log(result.message) // "Check je email voor de magic link!"
}
// Demo account login
async function handleDemoLogin() {
await loginWithPassword('demo@mini-ecd.demo', 'Demo2024!')
router.push('/clients')
}
// Check current user
const user = await getUser()
const isDemo = await isDemoUser()
// Logout
await logout() // Redirects to /login
```
### Server-Side (API Routes, Server Components)
```typescript
import {
requireAuth,
getUser,
canWrite,
getDemoUserInfo
} from '@/lib/auth/server'
// Require authentication in API route
export async function GET() {
const session = await requireAuth() // Throws if not authenticated
// ... handle request
}
// Check write permissions
export async function POST() {
const hasWriteAccess = await canWrite()
if (!hasWriteAccess) {
return NextResponse.json(
{ error: 'Read-only demo account cannot create data' },
{ status: 403 }
)
}
// ... create resource
}
// Get demo user info
const demoInfo = await getDemoUserInfo()
if (demoInfo) {
console.log(`Access level: ${demoInfo.access_level}`)
console.log(`Usage count: ${demoInfo.usage_count}`)
}
```
---
## Route Protection
Routes are protected via `middleware.ts`:
### Public Routes (No Auth Required)
- `/` - Landing page
- `/login` - Login page
- `/epd` - EPD demo info
- `/contact` - Contact form
- `/auth/callback` - Auth callback
### Protected Routes (Auth Required)
- `/clients` - Client list
- `/clients/*` - Client details, intake, etc.
- Any other route not in public list
**Behavior:**
- ✅ Unauthenticated → Redirect to `/login?redirect=/original-path`
- ✅ Authenticated on `/login` → Redirect to `/clients`
- ✅ Session auto-refreshed in middleware
---
## Security Features
### ✅ Implemented
1. **RLS Policies**: All database queries filtered by `auth.uid()`
2. **Session Management**: Auto-refresh tokens via middleware
3. **Secure Cookies**: HTTP-only, secure flags set
4. **CSRF Protection**: Built-in Next.js CSRF protection
5. **Rate Limiting**: Supabase default (4 emails/hour)
6. **Demo User Tracking**: Usage count and last login tracked
### 🔒 Production Enhancements
For production deployment:
1. **Email Confirmation**: Enable email confirmation
2. **Password Requirements**: Enforce strong passwords
3. **MFA**: Add multi-factor authentication
4. **Session Timeout**: Implement auto-logout after inactivity
5. **IP Whitelisting**: Restrict demo accounts to specific IPs
6. **Audit Logging**: Enhanced tracking of all auth events
---
## Demo User Management
### Checking Demo Status
```typescript
// Check if user is demo user
const isDemo = await isDemoUser()
// Get access level
const accessLevel = await getDemoAccessLevel()
// Returns: 'read_only' | 'interactive' | 'presenter' | null
```
### Restricting Actions
```typescript
// In API route
const demoInfo = await getDemoUserInfo()
if (demoInfo?.access_level === 'read_only') {
return NextResponse.json(
{ error: 'This demo account is read-only' },
{ status: 403 }
)
}
```
### Resetting Demo Accounts
To reset a demo account (clear data, reset usage):
```sql
-- Reset usage count
UPDATE demo_users
SET usage_count = 0, last_login_at = NULL
WHERE access_level = 'interactive';
-- Or via Supabase Dashboard: Authentication → Users → Delete user data
```
---
## Troubleshooting
### Issue: Magic link not arriving
**Causes:**
- Email in spam folder
- Rate limit exceeded (4 emails/hour)
- Email provider blocking Supabase emails
**Solutions:**
1. Check spam folder
2. Wait 1 hour and try again
3. Use demo account instead
4. Configure custom SMTP in Supabase
### Issue: "Invalid login credentials"
**Causes:**
- Wrong email/password for demo account
- Demo user not created yet
**Solutions:**
1. Check credentials match exactly (case-sensitive)
2. Run seed script: `tsx scripts/seed-demo-users.ts`
3. Verify in Supabase Dashboard → Authentication → Users
### Issue: Redirect loop on /login
**Causes:**
- Middleware configuration error
- Session cookie issues
**Solutions:**
1. Clear browser cookies
2. Check middleware.ts public routes config
3. Verify `NEXT_PUBLIC_SUPABASE_URL` is correct
### Issue: "Row violates RLS policy" errors
**Causes:**
- User not properly authenticated
- Session expired
- RLS policies misconfigured
**Solutions:**
1. Logout and login again
2. Check `auth.uid()` returns valid UUID
3. Verify RLS policies allow user access
---
## Testing Checklist
### Magic Link Flow
- [ ] Can enter email on /login
- [ ] Magic link email received
- [ ] Clicking link redirects to /clients
- [ ] Session persists after page refresh
- [ ] New users auto-created on first login
### Demo Account Flow
- [ ] Can login with demo@mini-ecd.demo
- [ ] Can login with readonly@mini-ecd.demo
- [ ] Interactive account can create/edit data
- [ ] Read-only account blocked from editing
- [ ] Demo usage tracked in demo_users table
### Route Protection
- [ ] /clients redirects to /login when not authenticated
- [ ] /login redirects to /clients when authenticated
- [ ] Public routes accessible without auth
- [ ] Session auto-refreshes
### Logout
- [ ] Logout clears session
- [ ] Redirects to /login
- [ ] Cannot access protected routes after logout
---
## References
- [Supabase Auth Documentation](https://supabase.com/docs/guides/auth)
- [Next.js Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware)
- Build Plan: `docs/specs/bouwplan-ai-speedrun-marketing-first-v1.1.md` Epic 2
- Technical Design: `docs/specs/to-mini-ecd-v1_2.md` § 5.7
---
**Status:** ✅ Implemented and Ready for Testing
**Next Steps:** E2.S4 - Seed data script (clients + dossiers)