Kairo-Jinkendo/docs/reference/design-principles/mitai/AUTH_SESSION_DESIGN_PRINCIPLES.md

327 lines
13 KiB
Markdown
Raw Normal View History

# Auth & Session – Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Authentifizierung, Session-Management, rollenbasierte API-Zugriffe — kein Mandanten-/SSO-System, keine Zahlungs-Auth
**Serie:** Designprinzipien für Produktfamilie · Dokument 5 von n
**Vorgänger:** [REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md](./REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Auth-Kern | `backend/auth.py` |
| Auth-Endpoints | `backend/routers/auth.py` |
| Profile | `backend/routers/profiles.py` |
| Frontend | `frontend/src/context/AuthContext.jsx`, `ProfileContext.jsx`, `utils/api.js` |
| DB | `profiles`, `sessions` |
| Architektur-Regeln | `.claude/rules/ARCHITECTURE.md`, `CLAUDE.md` § Auth |
| Vision (nicht implementiert) | `CENTRAL_SUBSCRIPTION_SYSTEM.md` (SSO/JWT) |
---
## Modul
**Auth & Session**
Server-seitige, token-basierte Authentifizierung mit FastAPI-Dependencies — **Identität und Rolle**, getrennt von Feature-Entitlements und fachlicher Logik.
---
## Fachliche Verantwortung
Das Modul übernimmt:
1. **Identität** — Wer ist eingeloggt? (`profiles` + Passwort/bcrypt)
2. **Session** — Opaque Token in `sessions`, Ablaufzeit, Logout
3. **API-Gate** — `require_auth`, `require_admin`, `require_auth_flexible`
4. **Passwort-Lifecycle** — Hash, Verify, Reset, Registrierung, E-Mail-Verifizierung
5. **Rollen** — `profiles.role`: `user` \| `admin` (grobbinsenartig)
Es übernimmt **nicht**:
- Feature-Limits / Tier (→ Feature & Entitlement System, gleiche `auth.py`-Datei aber logisch getrennt)
- Mandanten-Isolation / Org-Workspaces
- OAuth/SSO/JWT (nur Vision)
- Authorization auf Datensatzebene (Row-Level Security)
### Was Mitai **ist** vs. **nicht ist**
| Mitai | Produktfamilien-Muster |
|-------|------------------------|
| 1 Login = 1 Profil (E-Mail) | ✅ Account-Modell |
| Historisch Multi-Profil auf einer Instanz | ⚠️ Legacy (`/profiles`, `X-Profile-Id`) |
| Self-hosted Einzelinstanz | ✅ Kein Multi-Tenant-SaaS |
| Session-Token in DB | ✅ Server-side Session Store |
| Zentrale Jinkendo-Auth (Vision) | ❌ nicht gebaut |
---
## Administrierte vs. code-definierte Konfiguration
| Konfiguration | Speicherort | Administrierbar? |
|---------------|-------------|------------------|
| Nutzer-Stammdaten, Rolle | `profiles` | Admin (User-Verwaltung) / Self-Service |
| Session-Laufzeit | `profiles.session_days` (Default 30) | Profil/Admin |
| Passwort-Hash | `profiles.pin_hash` | Nutzer (change pin) |
| E-Mail-Verifizierung | `email_verified`, Token-Felder | System |
| Trial-Ende | `trial_ends_at` | System bei Registrierung |
| SMTP | Env (`SMTP_*`, `APP_URL`) | Deploy |
| Rate Limits Login/Register | Code (`5/min`, `3/hour`) | Code |
**Hardcodiert:** bcrypt, Token-Länge (`secrets.token_urlsafe(32)`), Rollen-Enum (`user`/`admin`), Header-Name `X-Auth-Token`.
---
## Session- und Auth-Flow
```
Login (email + password)
→ verify_pin (bcrypt | legacy SHA256)
→ optional bcrypt upgrade
→ INSERT sessions (token, profile_id, expires_at)
→ Client: localStorage bodytrack_token
Request
→ Header X-Auth-Token (api.js / AuthContext)
→ get_session(token) JOIN profiles
→ require_auth → session dict (profile_id, role, …)
Logout
→ DELETE sessions WHERE token=…
→ Client: localStorage clear
```
**Sonderfall:** `require_auth_flexible` — Token via Header **oder** Query `ssetoken` (SSE, `<img>`, Downloads).
---
## Rollen
| Rolle | Mechanismus | Typische Rechte |
|-------|-------------|-----------------|
| **user** | `profiles.role = 'user'` | Eigene Daten, Features nach Tier |
| **admin** | `require_admin` | Admin-Shell, Prompts, User, System |
Kein feingranulares RBAC (keine Permission-Matrix). Admin ist Binär-Schalter.
---
## Designprinzipien
### 1. FastAPI-Dependencies als Auth-Gate
| | |
|---|---|
| **Prinzip** | Jeder geschützte Endpoint nutzt `session: dict = Depends(require_auth)` als **separaten** Parameter — nie in `Header()` eingebettet. |
| **Begründung** | Verhindert ungeschützte Endpoints durch falsche Parameter-Signatur. |
| **Quelle** | `CLAUDE.md` § Kritische Regeln; `auth.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht linter-erzwungen; Legacy-Endpoints existieren. |
### 2. Server-side opaque Sessions
| | |
|---|---|
| **Prinzip** | Token ist zufällig, in DB gespeichert; Validierung über `sessions` + Ablauf — kein JWT mit Client-Claims. |
| **Begründung** | Revocation (Logout), kein Trust in Client-Payload; einfaches Modell für Self-Hosted. |
| **Quelle** | `sessions` Tabelle; `make_token()`, `get_session()` |
| **Tragfähigkeit** | **hoch** (Single-App, Self-Hosted) |
| **Einschränkung** | Skalierung multi-node braucht shared session store; SSO-Familie braucht anderes Modell. |
### 3. profile_id aus Session, nicht aus Client
| | |
|---|---|
| **Prinzip** | Autoritative Identität für neue Endpoints: `session['profile_id']` — Client darf Profil nicht wählen. |
| **Begründung** | Verhindert IDOR (Zugriff auf fremde Profile). |
| **Quelle** | `routers/goals.py`, `routers/prompts.py`; Architektur-Intent in `CLAUDE.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Legacy `get_pid(x_profile_id)` akzeptiert `X-Profile-Id` **ohne** Session-Abgleich — siehe Nicht übernehmen. |
### 4. bcrypt mit Legacy-Migration
| | |
|---|---|
| **Prinzip** | Passwörter mit bcrypt; SHA256-Legacy beim Login erkannt und transparent auf bcrypt upgraded. |
| **Begründung** | Kein Big-Bang-Migration; sichere Hashes ohne Nutzer-Zwangs-Reset. |
| **Quelle** | `verify_pin()`, Login in `routers/auth.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Upgrade nur bei erfolgreichem Login. |
### 5. Rate Limiting auf Auth-Endpoints
| | |
|---|---|
| **Prinzip** | Login, Register, Forgot-Password, Resend-Verification mit `slowapi`-Limits (IP-basiert). |
| **Begründung** | Brute-Force- und Abuse-Schutz. |
| **Quelle** | `routers/auth.py` (`5/minute`, `3/hour`); `main.py` Limiter |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | IP-only; kein account-based lockout. |
### 6. Keine E-Mail-Enumeration bei sensiblen Flows
| | |
|---|---|
| **Prinzip** | Forgot-Password und Resend-Verification liefern generische Erfolgsmeldung, auch wenn E-Mail unbekannt. |
| **Begründung** | Privacy; erschwert Account-Scraping. |
| **Quelle** | `password_reset_request`, `resend_verification` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Register sagt „E-Mail bereits registriert“ (Enumeration möglich). |
### 7. E-Mail-Verifizierung vor voller Nutzung
| | |
|---|---|
| **Prinzip** | Self-Register setzt `email_verified=FALSE`; Verify-Endpoint aktiviert + Auto-Login-Session. |
| **Begründung** | Valide Kontaktadresse; Spam-Reduktion. |
| **Quelle** | `register`, `verify_email` in `routers/auth.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht überall im Backend erzwungen (Login ohne verified check?). |
### 8. Flexible Auth für technische Clients
| | |
|---|---|
| **Prinzip** | `require_auth_flexible`: gleiche Session-Validierung via Header oder `?ssetoken=` für SSE/Bilder. |
| **Begründung** | Browser-APIs ohne Custom Headers. |
| **Quelle** | `auth.py`; Prompt SSE `/execute-stream` |
| **Tragfähigkeit** | **mittel–hoch** |
| **Einschränkung** | Token in URL kann in Logs/Referrer leaken — kurze Sessions / HTTPS Pflicht. |
### 9. Zentraler API-Client mit Token-Injektion
| | |
|---|---|
| **Prinzip** | Frontend: `api.js` injiziert `X-Auth-Token` automatisch — kein scattered `fetch` ohne Auth. |
| **Begründung** | Konsistenz; eine Stelle für Token-Handling. |
| **Quelle** | `utils/api.js` → `hdrs()`; `getToken()` aus AuthContext |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Einzelne Komponenten umgehen noch `api.js` (SettingsPage, EmailSettings). |
### 10. Auth getrennt von Authorization (Features)
| | |
|---|---|
| **Prinzip** | `require_auth` = identifiziert; `check_feature_access` = berechtigt für Aktion — nacheinander im Router. |
| **Begründung** | Klare Schichten; Auth-Modul nicht mit Tier-Logik vermischen (auch wenn Datei `auth.py` beides enthält). |
| **Quelle** | `FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md`; Router-Muster |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Legacy Profil-Flags `ai_enabled`, `export_enabled` parallel zum Feature-System. |
### 11. Admin-Gate im Frontend und Backend
| | |
|---|---|
| **Prinzip** | Backend: `require_admin`; Frontend: `RequireAdmin` + `isAdmin` aus Session-Rolle. |
| **Begründung** | UX-Navigation + API-Sicherheit (Frontend allein reicht nicht). |
| **Quelle** | `RequireAdmin.jsx`; `require_admin()` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Einzelne Routen (Workflow-Editor) ohne Frontend-Admin-Gate. |
### 12. Session-Kontext im Frontend
| | |
|---|---|
| **Prinzip** | `AuthProvider` hält `{ token, profile_id, role, profile }`; App setzt `setProfileId(session.profile_id)` für API. |
| **Begründung** | Single React-Tree für Login-State; Re-Validate via `/auth/me` beim Start. |
| **Quelle** | `AuthContext.jsx`; `App.jsx` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | `ProfileContext` lädt alle Profile — Multi-Profil-UX Rest; Session-Profil ist Kanon. |
---
## Nicht übernehmen
1. **`get_pid(X-Profile-Id)` ohne Session-Bindung** — Client kann fremde `profile_id` senden; IDOR-Risiko. Kanon: immer `session['profile_id']` oder explizite Admin-Impersonation mit Audit.
2. **Profile-CRUD nur mit `require_auth`** — `/profiles` listet alle Nutzer für jeden Authentifizierten (Kommentar „admin“, kein `require_admin`). Für Familien-Architektur: strikte Admin-Gates.
3. **Dual-System Profil-Flags vs. Features** — `ai_enabled`, `export_enabled`, `ai_limit_day` in Session-Query neben v9c Feature-Registry.
4. **localStorage-Key-Inkonsistenz** — `bodytrack_token` vs. `mitai-jinkendo_active_profile` (historischer App-Name).
5. **Direktes `fetch` ohne `api.js`** — umgeht Token-/Error-Konvention.
6. **Reset-Token in `sessions`-Tabelle** — `reset_{token}` mischt Session-Typen in einer Tabelle; OK für MVP, für Familie: getrennte Token-Typen/Tabellen.
7. **Kein JWT/SSO trotz Produktfamilien-Vision** — `CENTRAL_SUBSCRIPTION_SYSTEM.md` beschreibt `auth.jinkendo.de` — Mitai-Implementierung ist **nicht** das Zielbild für Cross-App-SSO.
8. **Multi-Profil-Haushalt ohne klares Modell** — Legacy Multi-Profile auf einer Instanz vs. 1 Account = 1 Profil; für neue Apps Modell explizit wählen.
9. **Role als einziges RBAC** — reicht für Admin/User, nicht für feingranulare Permissions.
10. **Session-Query mit veralteten Profil-Spalten** — `get_session` SELECT enthält Legacy-Felder statt nur Identität + Rolle.
11. **Fehlende erzwungene E-Mail-Verified-Prüfung** — Registrierung setzt Flag, Login prüft es nicht offensichtlich.
12. **Debug-Print in Auth-Modul** — `print("[AUTH.PY] Module loaded…")` in Produktionscode.
---
## Abgrenzung zu anderen Serien-Dokumenten
| Thema | Dokument |
|-------|----------|
| Tier, Limits, Quotas | [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](./FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md) |
| Zentrale SSO/Abo-Vision | [CENTRAL_SUBSCRIPTION_SYSTEM.md](../../technical/CENTRAL_SUBSCRIPTION_SYSTEM.md) |
| API-First / Router | `ARCHITECTURE.md` §1 |
---
## Modul-Inventar (Ist-Stand)
```
backend/
├── auth.py # Session, require_*, Feature-Access (v9c)
└── routers/
├── auth.py # login, logout, register, verify, reset
└── profiles.py # CRUD, get_pid (Legacy)
frontend/src/
├── context/AuthContext.jsx
├── context/ProfileContext.jsx
├── layouts/RequireAdmin.jsx
└── utils/api.js # Token-Injektion
DB:
├── profiles # Identität, Rolle, Hash, Tier, Trial
└── sessions # token → profile_id, expires_at
```
**Endpoints (Auswahl):**
| Endpoint | Auth |
|----------|------|
| `POST /api/auth/login` | Public + Rate limit |
| `POST /api/auth/logout` | Token optional |
| `GET /api/auth/me` | require_auth |
| `POST /api/auth/register` | Public + Rate limit |
| `GET /api/auth/verify/{token}` | Public |
---
## Verwandte Dokumentation
- Feature-Entitlements: [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](./FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md)
- Architektur-Regeln Auth: `CLAUDE.md`, `.claude/rules/ARCHITECTURE.md`
- GUI Admin-Guard: `docs/issues/GUI_IA_ADMIN_NAV_2026-04-05.md`
- SSO-Vision: [CENTRAL_SUBSCRIPTION_SYSTEM.md](../../technical/CENTRAL_SUBSCRIPTION_SYSTEM.md)
---
## Geplante Folgedokumente (Serie)
| # | Modul | Status |
|---|-------|--------|
| 1 | Prompt Engine | ✅ |
| 2 | Data Layer | ✅ |
| 3 | Feature & Entitlement | ✅ |
| 4 | Registry-/Plugin-Muster | ✅ |
| 5 | Auth & Session | ✅ dieses Dokument |
| 6 | Universal Import | ✅ `UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md` |
| 7 | Dashboard Widgets | ✅ |
| 8 | Navigation / IA | ✅ `NAVIGATION_IA_DESIGN_PRINCIPLES.md` |
| 9 | Migration & Deploy | ✅ |