# 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, ``, 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 | ✅ |