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

9.7 KiB

🔐 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

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:

# 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:

# 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:

<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)

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)

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

// 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

// 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):

-- 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

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

  • 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

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


Status: Implemented and Ready for Testing Next Steps: E2.S4 - Seed data script (clients + dossiers)