docs: improve auth flow documentation and fix email confirmation redirect
**Auth Callback Improvements:** - Fix default redirect from /clients to /epd/clients (correct route) - Add smart detection for password vs magic link users - Password signup users now go directly to /epd/clients after email confirmation - Magic link users still get optional /set-password page **Documentation:** - Add comprehensive AUTH_FLOW_EXPLAINED.md with step-by-step flow diagrams - Update RELEASE_AUTH_IMPROVEMENTS.md with magic link migration instructions - Update emails/README.md with aispeedrun.nl redirect URL configuration - Document Site URL vs Redirect URLs difference - Add troubleshooting for common issues (localhost in emails, invalid redirect) **Key Changes:** - Email confirmation now correctly redirects password users to EPD - Clear instructions for Supabase configuration (Site URL + Redirect URLs) - Both development and production URLs documented for dual environment support All documentation includes practical examples and FAQ section. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ import type { NextRequest } from 'next/server'
|
|||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
const requestUrl = new URL(request.url)
|
const requestUrl = new URL(request.url)
|
||||||
const code = requestUrl.searchParams.get('code')
|
const code = requestUrl.searchParams.get('code')
|
||||||
const next = requestUrl.searchParams.get('next') ?? '/clients'
|
const next = requestUrl.searchParams.get('next') ?? '/epd/clients'
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
const supabase = await createClient()
|
const supabase = await createClient()
|
||||||
@@ -25,12 +25,18 @@ export async function GET(request: NextRequest) {
|
|||||||
const isNewUser = new Date(data.user.created_at).getTime() ===
|
const isNewUser = new Date(data.user.created_at).getTime() ===
|
||||||
new Date(data.user.last_sign_in_at || '').getTime()
|
new Date(data.user.last_sign_in_at || '').getTime()
|
||||||
|
|
||||||
if (isNewUser) {
|
// Check if user signed up with password (has identity provider = 'email')
|
||||||
// Redirect new users to set-password page
|
const hasPassword = data.user.identities?.some(
|
||||||
|
identity => identity.provider === 'email'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isNewUser && !hasPassword) {
|
||||||
|
// Redirect new magic link users to set-password page (optional)
|
||||||
return NextResponse.redirect(new URL('/set-password', request.url))
|
return NextResponse.redirect(new URL('/set-password', request.url))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the specified next URL or default to /clients
|
// Redirect to the specified next URL or default to /epd/clients
|
||||||
|
// This includes: password signups, confirmed email users, and returning users
|
||||||
return NextResponse.redirect(new URL(next, request.url))
|
return NextResponse.redirect(new URL(next, request.url))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
206
docs/AUTH_FLOW_EXPLAINED.md
Normal file
206
docs/AUTH_FLOW_EXPLAINED.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Hoe werkt de Authenticatie Flow? 🔐
|
||||||
|
|
||||||
|
Een simpele uitleg van wat er gebeurt wanneer gebruikers zich aanmelden.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📧 Email Confirmatie Flow (nieuwe gebruikers)
|
||||||
|
|
||||||
|
### Stap 1: Gebruiker meldt zich aan
|
||||||
|
```
|
||||||
|
Gebruiker vult in op /login:
|
||||||
|
├─ Email: jan@example.com
|
||||||
|
└─ Wachtwoord: Geheim123!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 2: Supabase stuurt email
|
||||||
|
```
|
||||||
|
Supabase maakt account aan → Stuurt bevestigingsmail
|
||||||
|
|
||||||
|
De email bevat een link zoals:
|
||||||
|
https://aispeedrun.nl/auth/callback?token=xyz123&type=signup
|
||||||
|
└─────┬─────┘
|
||||||
|
Dit is de redirect URL!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 3: Gebruiker klikt op link in email
|
||||||
|
```
|
||||||
|
Browser gaat naar: /auth/callback?token=xyz123
|
||||||
|
|
||||||
|
De callback route doet:
|
||||||
|
1. ✅ Controleert de token
|
||||||
|
2. ✅ Activeert het account
|
||||||
|
3. ✅ Logt gebruiker in
|
||||||
|
4. → Stuurt door naar /epd/clients (omdat ze al wachtwoord hebben)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔑 Wachtwoord Reset Flow
|
||||||
|
|
||||||
|
### Stap 1: Gebruiker klikt "Wachtwoord vergeten?"
|
||||||
|
```
|
||||||
|
Gaat naar: /reset-password
|
||||||
|
Vult in: jan@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 2: Supabase stuurt reset email
|
||||||
|
```
|
||||||
|
Email bevat link:
|
||||||
|
https://aispeedrun.nl/auth/callback?token=abc789&type=recovery&next=/update-password
|
||||||
|
└─────┬─────┘ └────┬────┘
|
||||||
|
Callback route Waar naartoe daarna?
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 3: Gebruiker klikt link
|
||||||
|
```
|
||||||
|
/auth/callback ontvangt de token
|
||||||
|
├─ Controleert token ✅
|
||||||
|
├─ Logt gebruiker tijdelijk in
|
||||||
|
└─ Redirect naar: /update-password (van de 'next' parameter)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 4: Nieuw wachtwoord instellen
|
||||||
|
```
|
||||||
|
Op /update-password:
|
||||||
|
├─ Gebruiker vult nieuw wachtwoord in
|
||||||
|
├─ Wachtwoord wordt opgeslagen
|
||||||
|
└─ Redirect naar /login → Gebruiker kan inloggen!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✉️ Magic Link Flow (oude methode)
|
||||||
|
|
||||||
|
### Stap 1: Gebruiker vraagt magic link aan
|
||||||
|
```
|
||||||
|
Vult alleen email in (geen wachtwoord)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 2: Email met magic link
|
||||||
|
```
|
||||||
|
Link: https://aispeedrun.nl/auth/callback?token=magic456
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 3: Eerste keer inloggen
|
||||||
|
```
|
||||||
|
/auth/callback detecteert: "nieuwe magic link gebruiker"
|
||||||
|
└─ Redirect naar /set-password (optioneel wachtwoord instellen)
|
||||||
|
├─ Wachtwoord instellen → /epd/clients
|
||||||
|
└─ Overslaan → /epd/clients (blijf magic link gebruiken)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Waarom de Redirect URLs belangrijk zijn
|
||||||
|
|
||||||
|
Supabase moet weten welke URLs **veilig** zijn om naar terug te sturen.
|
||||||
|
|
||||||
|
### Zonder redirect URLs in Supabase:
|
||||||
|
```
|
||||||
|
❌ Link in email: https://aispeedrun.nl/auth/callback?token=xyz
|
||||||
|
↓
|
||||||
|
Supabase zegt: "Deze URL ken ik niet, BLOCKED!"
|
||||||
|
↓
|
||||||
|
Gebruiker ziet error 😞
|
||||||
|
```
|
||||||
|
|
||||||
|
### Met redirect URLs in Supabase:
|
||||||
|
```
|
||||||
|
✅ Link in email: https://aispeedrun.nl/auth/callback?token=xyz
|
||||||
|
↓
|
||||||
|
Supabase zegt: "Deze URL staat in mijn lijst, OK!"
|
||||||
|
↓
|
||||||
|
Gebruiker wordt ingelogd en doorgestuurd 🎉
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 De Site URL vs Redirect URLs
|
||||||
|
|
||||||
|
### Site URL (1 URL)
|
||||||
|
```
|
||||||
|
Dit is je "hoofd" URL waar Supabase denkt dat je app draait.
|
||||||
|
|
||||||
|
Supabase gebruikt dit voor:
|
||||||
|
├─ {{ .ConfirmationURL }} in emails (de basis)
|
||||||
|
└─ Default redirects
|
||||||
|
|
||||||
|
Development: http://localhost:3000
|
||||||
|
Production: https://aispeedrun.nl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Redirect URLs (meerdere URLs mogelijk)
|
||||||
|
```
|
||||||
|
Dit is de "whitelist" van URLs waar Supabase naartoe MAG redirecten.
|
||||||
|
|
||||||
|
Je moet ALLE mogelijke auth callbacks toevoegen:
|
||||||
|
├─ /auth/callback → Email confirmaties, magic links
|
||||||
|
├─ /update-password → Na password reset
|
||||||
|
├─ /set-password → Nieuwe users (optioneel wachtwoord)
|
||||||
|
└─ /reset-password → Password reset pagina
|
||||||
|
|
||||||
|
Voor zowel localhost als productie!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Simpel Gezegd
|
||||||
|
|
||||||
|
1. **Site URL** = Waar draait je app?
|
||||||
|
- Tijdens development: `http://localhost:3000`
|
||||||
|
- Live op internet: `https://aispeedrun.nl`
|
||||||
|
|
||||||
|
2. **Redirect URLs** = Welke paginas mag Supabase bezoeken na login/reset?
|
||||||
|
- Voeg ALLE auth-gerelateerde URLs toe
|
||||||
|
- Voor zowel development als productie
|
||||||
|
|
||||||
|
3. **Email links** = Gebouwd met Site URL + token
|
||||||
|
- Als Site URL = localhost → emails gaan naar localhost ❌
|
||||||
|
- Als Site URL = aispeedrun.nl → emails gaan naar je website ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Voorbeeld Flow in de Praktijk
|
||||||
|
|
||||||
|
```
|
||||||
|
[Gebruiker]
|
||||||
|
↓ Registreert op /login
|
||||||
|
[Jouw App]
|
||||||
|
↓ POST naar Supabase "maak account"
|
||||||
|
[Supabase]
|
||||||
|
↓ Stuurt email naar gebruiker
|
||||||
|
↓ Email link = [Site URL]/auth/callback?token=xyz
|
||||||
|
[Email Inbox]
|
||||||
|
↓ Gebruiker klikt link
|
||||||
|
[Browser]
|
||||||
|
↓ Gaat naar aispeedrun.nl/auth/callback?token=xyz
|
||||||
|
[Supabase]
|
||||||
|
↓ Checkt: staat "aispeedrun.nl/auth/callback" in Redirect URLs?
|
||||||
|
↓ JA ✅ → Verifieert token
|
||||||
|
[Jouw App - /auth/callback route]
|
||||||
|
↓ Token geldig? → Login gebruiker
|
||||||
|
↓ Nieuwe gebruiker met wachtwoord?
|
||||||
|
↓ JA → Redirect naar /epd/clients
|
||||||
|
[Gebruiker is ingelogd! 🎉]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❓ Veelgestelde Vragen
|
||||||
|
|
||||||
|
### Waarom krijg ik localhost links in productie emails?
|
||||||
|
→ Je Site URL staat nog op `http://localhost:3000` in Supabase. Wijzig naar `https://aispeedrun.nl`
|
||||||
|
|
||||||
|
### Waarom krijg ik "Invalid Redirect URL" errors?
|
||||||
|
→ De URL staat niet in je Redirect URLs lijst. Voeg hem toe in Supabase Dashboard.
|
||||||
|
|
||||||
|
### Kan ik zowel localhost als productie tegelijk gebruiken?
|
||||||
|
→ JA! Voeg beide toe aan Redirect URLs. Wissel alleen de Site URL afhankelijk van waar je test.
|
||||||
|
|
||||||
|
### Moet ik www. ook toevoegen?
|
||||||
|
→ Als je site bereikbaar is via `www.aispeedrun.nl`, voeg dan ook die URLs toe.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Hopelijk is het nu duidelijk! 🚀**
|
||||||
@@ -49,6 +49,40 @@ Alle foutmeldingen zijn nu duidelijker en helpen je beter op weg:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 📋 Voor Bestaande Magic Link Gebruikers
|
||||||
|
|
||||||
|
Heb je je eerder aangemeld met een magic link en wil je nu ook met een wachtwoord kunnen inloggen? Dat kan!
|
||||||
|
|
||||||
|
### Hoe stel je een wachtwoord in?
|
||||||
|
|
||||||
|
1. **Ga naar de wachtwoord reset pagina**
|
||||||
|
- Klik op "Wachtwoord vergeten?" op de login pagina
|
||||||
|
- Of ga direct naar `/reset-password`
|
||||||
|
|
||||||
|
2. **Vul je email in**
|
||||||
|
- Gebruik hetzelfde emailadres waarmee je via magic link inlogt
|
||||||
|
- Klik op "Stuur Reset Link"
|
||||||
|
|
||||||
|
3. **Check je inbox**
|
||||||
|
- Je ontvangt binnen enkele minuten een email
|
||||||
|
- Klik op de link in de email (geldig voor 1 uur)
|
||||||
|
|
||||||
|
4. **Stel je wachtwoord in**
|
||||||
|
- Kies een sterk wachtwoord (minimaal 8 tekens)
|
||||||
|
- Bevestig het wachtwoord
|
||||||
|
- Klaar!
|
||||||
|
|
||||||
|
### Na het instellen van een wachtwoord
|
||||||
|
|
||||||
|
Je kunt nu kiezen hoe je wilt inloggen:
|
||||||
|
|
||||||
|
- 🔑 **Met wachtwoord** - Sneller, direct inloggen zonder email te checken
|
||||||
|
- ✉️ **Met magic link** - Blijft ook gewoon werken zoals voorheen
|
||||||
|
|
||||||
|
Beide methodes blijven beschikbaar, je kiest zelf wat je het prettigst vindt!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🚀 Voor Ontwikkelaars
|
## 🚀 Voor Ontwikkelaars
|
||||||
|
|
||||||
De volgende functies zijn toegevoegd aan `lib/auth/client.ts`:
|
De volgende functies zijn toegevoegd aan `lib/auth/client.ts`:
|
||||||
|
|||||||
@@ -28,12 +28,38 @@ Deze directory bevat HTML email templates die gebruikt kunnen worden in Supabase
|
|||||||
|
|
||||||
## Hoe te gebruiken in Supabase
|
## Hoe te gebruiken in Supabase
|
||||||
|
|
||||||
|
### Stap 1: Site URL Configureren
|
||||||
|
|
||||||
|
**BELANGRIJK:** Zorg eerst dat je Site URL correct is ingesteld, anders verwijzen alle email links naar localhost!
|
||||||
|
|
||||||
1. Log in op je Supabase Dashboard
|
1. Log in op je Supabase Dashboard
|
||||||
2. Ga naar **Authentication** → **Email Templates**
|
2. Ga naar **Authentication** → **URL Configuration**
|
||||||
3. Selecteer het juiste template type (Confirm signup of Reset Password)
|
3. Stel de **Site URL** in:
|
||||||
4. Kopieer de volledige HTML inhoud van het corresponderende `.html` bestand
|
- **Development:** `http://localhost:3000`
|
||||||
5. Plak deze in het Supabase email template veld
|
- **Production:** `https://aispeedrun.nl`
|
||||||
6. Klik op **Save**
|
4. Voeg de volgende **Redirect URLs** toe (één per regel):
|
||||||
|
```
|
||||||
|
http://localhost:3000/auth/callback
|
||||||
|
http://localhost:3000/update-password
|
||||||
|
http://localhost:3000/set-password
|
||||||
|
http://localhost:3000/reset-password
|
||||||
|
https://aispeedrun.nl/auth/callback
|
||||||
|
https://aispeedrun.nl/update-password
|
||||||
|
https://aispeedrun.nl/set-password
|
||||||
|
https://aispeedrun.nl/reset-password
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Je kunt zowel localhost als productie URLs toevoegen, zodat beide omgevingen werken.
|
||||||
|
|
||||||
|
5. Klik op **Save**
|
||||||
|
|
||||||
|
### Stap 2: Email Templates Instellen
|
||||||
|
|
||||||
|
1. Ga naar **Authentication** → **Email Templates**
|
||||||
|
2. Selecteer het juiste template type (Confirm signup of Reset Password)
|
||||||
|
3. Kopieer de volledige HTML inhoud van het corresponderende `.html` bestand
|
||||||
|
4. Plak deze in het Supabase email template veld
|
||||||
|
5. Klik op **Save**
|
||||||
|
|
||||||
## Design Kenmerken
|
## Design Kenmerken
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user