# Passwort-Reset per E-Mail — Design ## Flow 1. Nutzer klickt "Passwort vergessen?" auf der Login-Seite 2. Gibt E-Mail-Adresse ein → `POST /api/auth/forgot-password` 3. Backend generiert Token, speichert Hash in DB, sendet E-Mail mit Link 4. E-Mail enthält: `{FRONTEND_BASE_URL}/reset-password?token=XXX` (1h gültig) 5. Nutzer klickt Link → Frontend zeigt "Neues Passwort"-Formular 6. Nutzer gibt neues Passwort ein → `POST /api/auth/reset-password` 7. Backend validiert Token, setzt Passwort, invalidiert Token ## Backend ### Neues Modell: `PasswordResetToken` Felder: `id`, `user_id` (FK), `token_hash` (SHA-256), `expires_at` (1h), `used_at`, `created_at`. ### Endpoints - `POST /api/auth/forgot-password` — Immer 200 (verhindert User-Enumeration). Bei gültiger E-Mail: Token generieren, E-Mail senden. - `POST /api/auth/reset-password` — Token + neues Passwort. Validiert Token, setzt Passwort, invalidiert alle Reset-Tokens des Users. ### Config `FRONTEND_BASE_URL` in Settings für Reset-Link-Generierung. ### Sicherheit - Token: `secrets.token_urlsafe(32)`, gespeichert als SHA-256 Hash - 1h gültig, einmalig verwendbar - Rate-Limiting: Max 3 Requests pro E-Mail pro Stunde - Funktioniert auch bei gesperrten Accounts - Audit-Log: `password_reset_requested`, `password_reset_completed` ## Frontend - "Passwort vergessen?"-Link auf LoginPage - Inline E-Mail-Eingabe unter dem Login-Formular - Neue Route `/reset-password` → `ResetPasswordPage.tsx` - Formular: Neues Passwort + Bestätigung (min. 8 Zeichen) ## Dateien | Datei | Änderung | |-------|----------| | `backend/app/models/user.py` | `PasswordResetToken` Modell | | `backend/alembic/versions/007_password_reset_tokens.py` | Migration | | `backend/app/config.py` | `FRONTEND_BASE_URL` Setting | | `backend/app/api/auth.py` | Zwei neue Endpoints | | `frontend/src/pages/LoginPage.tsx` | "Passwort vergessen?" UI | | `frontend/src/pages/ResetPasswordPage.tsx` | Neue Seite | | `frontend/src/App.tsx` | Route `/reset-password` |