Adds AUTH-CFG settings, confirmation/recovery templates and docs/auth-konfiguration.md (KTO-01 criteria 1, 3, 4, 7, 8, 11). Refs #1 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
173 lines
18 KiB
Markdown
173 lines
18 KiB
Markdown
# Auth-Konfiguration (Supabase Auth / GoTrue)
|
||
|
||
| | |
|
||
|---|---|
|
||
| Gilt für | KTO-01 (Issue #1) und alle folgenden Auth-Stories |
|
||
| Stand | 2026-11-02 |
|
||
| Versionen (verifiziert) | Supabase CLI 3.0.0, GoTrue `supabase/gotrue:v2.197.0`, Postgres 17, Mailpit v1.31.3 |
|
||
| Quellen | `docs/specs/1-auth-registrierung-anmeldung.md` (§ 4.1, 4.3), `docs/specs/1-auth-spike-ergebnisse.md` (Nachweis, bleibt unverändert liegen) |
|
||
| Pflege | Jede Änderung an `supabase/config.toml` (Abschnitt `[auth*]`) und am Env-Block unten gemeinsam ändern. Tests referenzieren die IDs `AUTH-CFG-nn`. |
|
||
|
||
Zweck: Die Auth-Einstellungen sind explizit festgelegt, weil sich die Standardwerte je nach Quelle unterscheiden (GoTrue-Binary, CLI-Vorlage, Docker-Setup; Klärung 18). Lokal und in der CI gilt `supabase/config.toml`. Staging und Produktion (self-hosted, ADR-0002) setzen dieselben Werte per Umgebungsvariablen.
|
||
|
||
## 1. Einstellungen (AUTH-CFG)
|
||
|
||
Spalte „Wirkung“: **lokal** = wirkt in der CLI über `config.toml`; **Env** = wirkt nur im Self-Hosting über Umgebungsvariablen (in `config.toml` nur als Kommentar bzw. Zielwert); **Gateway** = nur am Proxy/Gateway lösbar.
|
||
|
||
| ID | Einstellung | Wert | Wirkung | `config.toml` / Env | Begründung | Krit. |
|
||
|---|---|---|---|---|---|---|
|
||
| AUTH-CFG-01 | Site-URL | lokal `http://localhost:3000`; Prod `https://shuffle.cshomelabs.work` (Platzhalter); Staging legt devops fest | lokal + Env | `auth.site_url` / `GOTRUE_SITE_URL` | Basis der Mail-Links (`{{ .SiteURL }}`) | 1, 8 |
|
||
| AUTH-CFG-02 | Redirect-Allow-List | nur `<Site-URL>/auth/confirm` | lokal + Env | `auth.additional_redirect_urls` / `GOTRUE_URI_ALLOW_LIST` | Nur eigene Web-URLs erlaubt | 1, 8 |
|
||
| AUTH-CFG-03 | Registrierung erlaubt | an | lokal + Env | `auth.enable_signup`, `auth.email.enabled` / `GOTRUE_DISABLE_SIGNUP=false`, `GOTRUE_EXTERNAL_EMAIL_ENABLED=true` | Selbstregistrierung ist der Kern von KTO-01 | 1 |
|
||
| AUTH-CFG-04 | E-Mail-Bestätigung Pflicht | an | lokal + Env | `auth.email.enable_confirmations = true` / `GOTRUE_MAILER_AUTOCONFIRM=false` | CLI-Standard ist `false`. Voraussetzung für den Enumerationsschutz, zusammen mit AUTH-CFG-24 | 1, 4, 6 |
|
||
| AUTH-CFG-05 | Passwort-Mindestlänge | 10 | lokal + Env | `auth.minimum_password_length` / `GOTRUE_PASSWORD_MIN_LENGTH` | Entscheidung O10; Standard wäre 6 | 3 |
|
||
| AUTH-CFG-06 | Zeichenklassen | keine | lokal + Env | `auth.password_requirements = ""` / `GOTRUE_PASSWORD_REQUIRED_CHARACTERS` leer | Nicht gefordert | 3 |
|
||
| AUTH-CFG-07 | Gültigkeit Bestätigungs- und Reset-Link | 3600 s (1 h) | lokal + Env | `auth.email.otp_expiry` / `GOTRUE_MAILER_OTP_EXP=3600` | Entscheidung F3. Das Self-hosted-Binary hätte 86400, deshalb im Env explizit setzen | 1, 8 |
|
||
| AUTH-CFG-08 | Mindestabstand zwischen Mails je Nutzer | lokal/CI 1 s; Staging/Prod 60 s | lokal + Env | `auth.email.max_frequency` / `GOTRUE_SMTP_MAX_FREQUENCY=60s` | Lokal bewusst 1 s, sonst scheitert der Resend-Test direkt nach dem Signup an 429. Die 60 s werden auf Staging geprüft (Checkliste) | 6, 8 |
|
||
| AUTH-CFG-09 | Mails pro Stunde, **instanzweit** | lokal/CI-Zielwert 100; Staging/Prod **30** | **nur Env** | `auth.rate_limit.email_sent` (lokal ohne Wirkung) / `GOTRUE_RATE_LIMIT_EMAIL_SENT=30` | Entscheidung F4. Die CLI setzt intern `360000` (Spike A3). Risiko R3 | 1, 6, 8 |
|
||
| AUTH-CFG-10 | Drosselung Passwort-Login und Token-Refresh | 150 je 5 min je IP, Burst 30 | **nur Env, nur mit AUTH-CFG-13** | `auth.rate_limit.token_refresh` / `GOTRUE_RATE_LIMIT_TOKEN_REFRESH=150` | Login Nr. 31 einer IP → 429 `over_request_rate_limit`. Keine Sperre je Konto, nur je IP. 429 ohne `Retry-After` | 7 |
|
||
| AUTH-CFG-11 | Drosselung Registrierung, Reset, erneut senden | 30 je 5 min je IP, Burst 30 | **nur Env, nur mit AUTH-CFG-13** | `auth.rate_limit.sign_in_sign_ups` / `GOTRUE_RATE_LIMIT_OTP=30` | Für Signup getestet; dass Recover und Resend denselben Limiter nutzen, ist nur aus dem Code abgeleitet | 1, 6, 8 |
|
||
| AUTH-CFG-12 | Drosselung Link-Prüfung | 30 je 5 min je IP | **nur Env, nur mit AUTH-CFG-13** | `auth.rate_limit.token_verifications` / `GOTRUE_RATE_LIMIT_VERIFY=30` | – | 8 |
|
||
| AUTH-CFG-13 | Client-IP hinter Proxy | `GOTRUE_RATE_LIMIT_HEADER=X-Forwarded-For` | **nur Env (Pflicht Staging/Prod)** | – / `GOTRUE_RATE_LIMIT_HEADER` | Ohne diese Einstellung gibt es **keine** IP-Drosselung; Requests ohne den Header werden auch mit ihr nicht gedrosselt. Der Proxy muss den Header überschreiben | 7 |
|
||
| AUTH-CFG-14 | JWT-Laufzeit | 3600 s | lokal + Env | `auth.jwt_expiry` / `GOTRUE_JWT_EXP=3600` | Entscheidung F1. Andere Geräte sind nach einem Passwort-Reset spätestens nach 60 min abgemeldet (Restrisiko R8) | 5, 9 |
|
||
| AUTH-CFG-15 | Refresh-Token-Rotation | an, Wiederverwendungsfenster 10 s | lokal + Env | `auth.enable_refresh_token_rotation`, `auth.refresh_token_reuse_interval` / `GOTRUE_SECURITY_REFRESH_TOKEN_ROTATION_ENABLED=true`, `GOTRUE_SECURITY_REFRESH_TOKEN_REUSE_INTERVAL=10` | Standard | 5, 9 |
|
||
| AUTH-CFG-16 | Sitzungsbegrenzung | **nicht gesetzt** | lokal + Env | `auth.sessions.*` (auskommentiert) / `GOTRUE_SESSIONS_TIMEBOX`, `GOTRUE_SESSIONS_INACTIVITY_TIMEOUT` ungesetzt | Angemeldet bis zum Abmelden | 5 |
|
||
| AUTH-CFG-17 | Mailvorlage Bestätigung | `supabase/templates/confirmation.html`, Betreff de/en | lokal + Env | `auth.email.template.confirmation` / `GOTRUE_MAILER_TEMPLATES_CONFIRMATION` (URL), `GOTRUE_MAILER_SUBJECTS_CONFIRMATION` | Sprache aus `user_metadata.locale`, sonst Englisch. Self-hosted lädt per URL (siehe 3) | 1, 11 |
|
||
| AUTH-CFG-18 | Mailvorlage Reset | `supabase/templates/recovery.html`, Betreff de/en | lokal + Env | `auth.email.template.recovery` / `GOTRUE_MAILER_TEMPLATES_RECOVERY`, `GOTRUE_MAILER_SUBJECTS_RECOVERY` | wie oben | 8, 11 |
|
||
| AUTH-CFG-19 | Benachrichtigungs-Mails | alle aus | lokal + Env | `auth.email.notification.<typ>.enabled = false` / `GOTRUE_MAILER_NOTIFICATIONS_<TYP>_ENABLED=false` | Nur Bestätigung und Reset (Krit. 11). `email_changed` schaltet KTO-11 ein (N2) | 11 |
|
||
| AUTH-CFG-20 | Magic Link / OTP-Login | `POST /auth/v1/otp` und `/auth/v1/magiclink` am Gateway sperren | **Gateway** | – (kein Schalter in GoTrue) | Sonst Mails außerhalb von Krit. 11 und Konten ohne Passwort (Spike A7). Der Trigger ersetzt die Sperre nicht. Lokal nicht gesperrt | 11, 3 |
|
||
| AUTH-CFG-21 | Leaked-Password-Prüfung (HIBP) | aus | **nur Env** | – / `GOTRUE_PASSWORD_HIBP_ENABLED=false` | Entscheidung F2: keine Übermittlung an Dritte | 3 |
|
||
| AUTH-CFG-22 | SMTP / Mailfänger | lokal Mailpit; Staging/Prod EU-Anbieter mit AVV (**offen**, F7) | lokal + Env | `local_smtp` / `GOTRUE_SMTP_*` | Release-Blocker, kein Merge-Blocker | 1, 8, 11 |
|
||
| AUTH-CFG-23 | E-Mail-Wechsel auf beiden Adressen bestätigen | **in #1 nicht festgelegt** (CLI-Standard `true`) | – | `auth.email.double_confirm_changes` / `GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED` | Entscheidung fällt in KTO-11 (N2) | (KTO-11) |
|
||
| AUTH-CFG-24 | SMS-Autoconfirm aus | `SMS_AUTOCONFIRM=false` | lokal + Env | `auth.sms.enable_confirmations = true` / `GOTRUE_SMS_AUTOCONFIRM=false`; in der Self-Hosting-Vorlage `ENABLE_PHONE_AUTOCONFIRM=false` | SMS ist nicht im Einsatz, die Einstellung steuert aber den Enumerationsschutz beim E-Mail-Signup. Mit `true` (CLI-Standard und Vorlage `docker/.env.example`!) liefert Signup mit bestätigter Adresse 422 `user_already_exists` | 4 |
|
||
|
||
Ohne eigene ID: `auth.email.secure_password_change = false` (Standard, ausdrücklich gesetzt). Recovery-Sitzungen sind davon ausgenommen; ob für die Passwortänderung das aktuelle Passwort verlangt wird, entscheidet KTO-11 (N13).
|
||
|
||
## 2. Env-Block für Staging und Produktion (GoTrue, ohne Secrets)
|
||
|
||
Gilt für das Image `supabase/gotrue:v2.197.0` (pinnen, nicht `latest`). Secrets (JWT-Secret, SMTP-Passwort, DB-URL) stehen nicht hier, sondern im Secret-Speicher des Hosting-Setups.
|
||
|
||
```env
|
||
# AUTH-CFG-01, -02, -03
|
||
GOTRUE_SITE_URL=https://shuffle.cshomelabs.work
|
||
GOTRUE_URI_ALLOW_LIST=https://shuffle.cshomelabs.work/auth/confirm
|
||
GOTRUE_DISABLE_SIGNUP=false
|
||
GOTRUE_EXTERNAL_EMAIL_ENABLED=true
|
||
|
||
# AUTH-CFG-04, -24 (beide Autoconfirm-Schalter müssen false sein; Supabase-Vorlage: ENABLE_PHONE_AUTOCONFIRM=false)
|
||
GOTRUE_MAILER_AUTOCONFIRM=false
|
||
GOTRUE_SMS_AUTOCONFIRM=false
|
||
|
||
# AUTH-CFG-05, -06, -21
|
||
GOTRUE_PASSWORD_MIN_LENGTH=10
|
||
GOTRUE_PASSWORD_REQUIRED_CHARACTERS=
|
||
GOTRUE_PASSWORD_HIBP_ENABLED=false
|
||
|
||
# AUTH-CFG-07, -08
|
||
GOTRUE_MAILER_OTP_EXP=3600
|
||
GOTRUE_SMTP_MAX_FREQUENCY=60s
|
||
|
||
# AUTH-CFG-09 bis -13 (GOTRUE_RATE_LIMIT_HEADER ist Pflicht, sonst keine IP-Drosselung)
|
||
GOTRUE_RATE_LIMIT_HEADER=X-Forwarded-For
|
||
GOTRUE_RATE_LIMIT_EMAIL_SENT=30
|
||
GOTRUE_RATE_LIMIT_TOKEN_REFRESH=150
|
||
GOTRUE_RATE_LIMIT_OTP=30
|
||
GOTRUE_RATE_LIMIT_VERIFY=30
|
||
|
||
# AUTH-CFG-14, -15 (AUTH-CFG-16: Sitzungs-Variablen NICHT setzen)
|
||
GOTRUE_JWT_EXP=3600
|
||
GOTRUE_SECURITY_REFRESH_TOKEN_ROTATION_ENABLED=true
|
||
GOTRUE_SECURITY_REFRESH_TOKEN_REUSE_INTERVAL=10
|
||
|
||
# AUTH-CFG-17, -18 (Betreff je Sprache verzweigt, Text identisch zu config.toml; URLs siehe Abschnitt 3)
|
||
GOTRUE_MAILER_TEMPLATES_CONFIRMATION=https://<vorlagen-host>/confirmation.html
|
||
GOTRUE_MAILER_TEMPLATES_RECOVERY=https://<vorlagen-host>/recovery.html
|
||
GOTRUE_MAILER_SUBJECTS_CONFIRMATION={{ if and .Data (eq (index .Data "locale") "de") }}Bestätige deine E-Mail-Adresse für Shuffle{{ else }}Confirm your email address for Shuffle{{ end }}
|
||
GOTRUE_MAILER_SUBJECTS_RECOVERY={{ if and .Data (eq (index .Data "locale") "de") }}Passwort für Shuffle zurücksetzen{{ else }}Reset your Shuffle password{{ end }}
|
||
|
||
# AUTH-CFG-19 (Benachrichtigungen aus; KTO-11 schaltet email_changed ein)
|
||
GOTRUE_MAILER_NOTIFICATIONS_PASSWORD_CHANGED_ENABLED=false
|
||
GOTRUE_MAILER_NOTIFICATIONS_EMAIL_CHANGED_ENABLED=false
|
||
GOTRUE_MAILER_NOTIFICATIONS_PHONE_CHANGED_ENABLED=false
|
||
GOTRUE_MAILER_NOTIFICATIONS_IDENTITY_LINKED_ENABLED=false
|
||
GOTRUE_MAILER_NOTIFICATIONS_IDENTITY_UNLINKED_ENABLED=false
|
||
GOTRUE_MAILER_NOTIFICATIONS_MFA_FACTOR_ENROLLED_ENABLED=false
|
||
GOTRUE_MAILER_NOTIFICATIONS_MFA_FACTOR_UNENROLLED_ENABLED=false
|
||
|
||
# AUTH-CFG-22 (Anbieter offen, F7): GOTRUE_SMTP_HOST, _PORT, _USER, _PASS, _ADMIN_EMAIL, _SENDER_NAME
|
||
```
|
||
|
||
Hinweis zu den Benachrichtigungs-Variablen: Namen aus dem GoTrue-Schema für `v2.197.0` abgeleitet; beim ersten Aufsetzen mit einer Testmail (Passwortänderung) prüfen, dass keine Mail ausgeht (Checkliste).
|
||
|
||
## 3. Gateway- und Dashboard-Einstellungen
|
||
|
||
- **Proxy vor GoTrue (AUTH-CFG-13):** GoTrue ist nur über den Proxy erreichbar. Der Proxy **überschreibt** `X-Forwarded-For` mit der echten Client-IP (nicht anhängen), sonst fälschen Clients ihre IP und umgehen die Drosselung. Ein direkter Zugriff auf GoTrue umgeht die Drosselung ebenfalls.
|
||
- **Magic-Link-Sperre (AUTH-CFG-20):** Das Gateway lehnt `POST /auth/v1/otp` und `POST /auth/v1/magiclink` ab (z. B. 404/403). Beide Endpunkte lassen sich in GoTrue nicht abschalten; `/otp` legt mit gültigen Metadaten ein Konto an.
|
||
- **Vorlagen-Hosting (AUTH-CFG-17, -18):** Self-hosted GoTrue lädt Mailvorlagen **per URL**. Die Dateien aus `supabase/templates/` werden unter einer intern erreichbaren URL bereitgestellt (z. B. statisch am Gateway). Ist die URL nicht erreichbar, fällt GoTrue **still** auf die englische Standardvorlage zurück (Risiko R5). Die URL gehört in den Health-Check.
|
||
- **SPA-Rewrite:** Die Web-App muss `/auth/confirm` ausliefern (alle Pfade → `index.html`), sonst laufen die Mail-Links ins Leere.
|
||
- **Dashboard:** Im Self-Hosting gibt es keine Cloud-Einstellungen; Studio ändert keine Auth-Werte. Alle Werte stehen im Env-Block oben. Änderungen im Studio sind zu unterlassen, damit Repo und Betrieb übereinstimmen.
|
||
- **Image-Pinning:** `supabase/gotrue:v2.197.0`. Die Postgres-Hauptversion 17 muss mit `db.major_version` übereinstimmen.
|
||
|
||
## 4. Verifiziert (Spike B0, 2026-11-02)
|
||
|
||
Getestet gegen CLI 3.0.0 und GoTrue `v2.197.0` über Kong (wie die App). Die Drosselungs- und Mail-Limit-Tests liefen zusätzlich gegen einen zweiten GoTrue-Container desselben Images mit den Env-Variablen der CLI plus `GOTRUE_RATE_LIMIT_HEADER=X-Forwarded-For` und `GOTRUE_RATE_LIMIT_EMAIL_SENT=5` (entspricht dem Self-Hosting-Pfad). Nicht aussagekräftig lokal: SMTP-Anbieter, Verhalten hinter dem Produktions-Gateway, Header-Behandlung des Proxys, echte Zustellung. Vollständige Nachweise: `docs/specs/1-auth-spike-ergebnisse.md`.
|
||
|
||
| Punkt | Ergebnis |
|
||
|---|---|
|
||
| (a) Betreff und Vorlage werten `.Data.locale` aus | Bestätigt. `de` → deutsch; `en` oder fehlend → englisch. `index .Data "locale"` ist sicher, wenn der Schlüssel fehlt. Nach Profiländerung (Sync-Trigger) kommt die Mail in der neuen Sprache. |
|
||
| (b) `type` für `token_hash` | Bestätigung `email` (auch `signup`), Reset `recovery`. Zweites Einlösen → 403 `otp_expired`. |
|
||
| (c) Limiter Passwort-Login | `GOTRUE_RATE_LIMIT_TOKEN_REFRESH` (150 je 5 min, Burst 30); Signup/Recover/Resend `GOTRUE_RATE_LIMIT_OTP` (30 je 5 min). **Greifen nur mit `GOTRUE_RATE_LIMIT_HEADER` und Requests mit dem Header.** Die lokale CLI kann den Header nicht setzen, also lokal keine Drosselung. 429 ohne `Retry-After`. |
|
||
| (d) `email_sent` | Instanzweit. In der CLI wirkungslos (`360000`). Bei erschöpftem Limit antwortet `/recover` für bestehende Adressen 429, für unbekannte 200 (Seitenkanal, akzeptiert F12). |
|
||
| (e) Mailfänger | Mailpit v1.31.3, `http://127.0.0.1:54324/api/v1/messages`, `/api/v1/message/{id}`. |
|
||
| (f) Trigger-Fehler bei `signUp` | HTTP 500, Header `X-Sb-Error-Code: unexpected_failure`, Body `{"code":"P0001","message":"<grund>"}`. Format nicht vertraglich zugesichert. |
|
||
| (g) `weak_password` | 422, `reasons = ["length"]`. |
|
||
| (h) Versionen | CLI 3.0.0 startet GoTrue `v2.197.0`, identisch zur `docker-compose.yml` des Supabase-Repos (Stand 2026-11-02). |
|
||
| (i) Linkablauf | Maßgeblich sind `auth.users.confirmation_sent_at` / `recovery_sent_at`, nicht `auth.one_time_tokens.created_at`. |
|
||
| (j) `amr` im Recovery-JWT | `[{"method":"otp"}]`, identisch zur Bestätigungssitzung; nicht unterscheidbar (R12). |
|
||
|
||
Abweichungen von der ursprünglichen Spec-Annahme:
|
||
|
||
| # | Abweichung | Konsequenz |
|
||
|---|---|---|
|
||
| A1 | Enumerationsschutz hängt an `GOTRUE_SMS_AUTOCONFIRM=false` (CLI-Standard und Self-Hosting-Vorlage setzen `true`). Sonst 422 `user_already_exists`. | AUTH-CFG-24 |
|
||
| A2 | Ohne `GOTRUE_RATE_LIMIT_HEADER` keine IP-Drosselung; Requests ohne Header werden auch mit Einstellung nicht gedrosselt. | AUTH-CFG-13 Pflicht; Drosselungstest gegen Extra-Container |
|
||
| A3 | `email_sent` wirkt in der CLI nicht. | AUTH-CFG-09 nur per Env |
|
||
| A4 | Trigger-Fehler kommen als HTTP 500 mit der Trigger-Meldung im Body. | Mapping über Status 500 |
|
||
| A5 | Recovery-JWT ist an `amr` nicht erkennbar. | Guard nur im laufenden Prozess |
|
||
| A6 | Linkablauf wird über `auth.users.*_sent_at` bestimmt. | E2E-Helfer setzt diese Spalten |
|
||
| A7 | `/otp` und `/magiclink` nicht abschaltbar, `/otp` kann Konten anlegen. | AUTH-CFG-20 am Gateway |
|
||
|
||
### Prüfung der Konfiguration und Mailvorlagen (B2, lokal)
|
||
|
||
Mit der committeten `config.toml` geprüft (Mailpit-API): Registrierung mit `locale=de` → Betreff „Bestätige deine E-Mail-Adresse für Shuffle“, `lang="de"`; `locale=en` und ohne `locale` → englischer Betreff und Text; Passwort-Reset analog („Passwort für Shuffle zurücksetzen“ / „Reset your Shuffle password“). Links: `http://localhost:3000/auth/confirm?token_hash=…&type=email` bzw. `…&type=recovery`; der Token aus der Mail lässt sich per `POST /verify` einlösen. Im GoTrue-Container sind `GOTRUE_MAILER_AUTOCONFIRM=false`, `GOTRUE_SMS_AUTOCONFIRM=false`, `GOTRUE_PASSWORD_MIN_LENGTH=10`, `GOTRUE_MAILER_OTP_EXP=3600` und `GOTRUE_URI_ALLOW_LIST=http://localhost:3000/auth/confirm` gesetzt. Signup mit 9 Zeichen → 422 `weak_password`; Signup mit bestätigter Adresse → 200 mit erfundenem Nutzer und leeren `identities`, keine Mail.
|
||
|
||
## 5. Release-Checkliste (vor jedem Release auf Staging/Produktion)
|
||
|
||
Automatisiert nicht abdeckbar (Spec § 7.1); vor dem Release abhaken:
|
||
|
||
- [ ] GoTrue-Image ist `supabase/gotrue:v2.197.0` (oder bewusst aktualisiert, dann Spike-Punkte (c), (d), (f) wiederholen).
|
||
- [ ] Env-Block aus Abschnitt 2 ist vollständig gesetzt; `GOTRUE_PASSWORD_HIBP_ENABLED=false` (AUTH-CFG-21).
|
||
- [ ] `GOTRUE_SMS_AUTOCONFIRM=false` bzw. `ENABLE_PHONE_AUTOCONFIRM=false`: Signup mit bestätigter Adresse → 200, `identities` leer (AUTH-CFG-24).
|
||
- [ ] Drosselung am echten Gateway: 31 Fehllogins einer IP → 429; ein vom Client gefälschter `X-Forwarded-For` wird überschrieben; GoTrue ist von außen nicht direkt erreichbar (AUTH-CFG-13, -10).
|
||
- [ ] `POST /auth/v1/otp` und `/auth/v1/magiclink` werden vom Gateway abgelehnt (AUTH-CFG-20).
|
||
- [ ] Mailvorlagen-URLs erreichbar; Testmail de und en (Bestätigung und Reset) auf Staging, Betreff und Text in der richtigen Sprache (AUTH-CFG-17, -18, Risiko R5).
|
||
- [ ] Mindestabstand 60 s zwischen Mails je Nutzer (AUTH-CFG-08) und Link-Gültigkeit 1 h (AUTH-CFG-07) auf Staging geprüft.
|
||
- [ ] `GOTRUE_RATE_LIMIT_EMAIL_SENT=30` gesetzt und Monitoring auf 429 `over_email_send_rate_limit` aktiv (AUTH-CFG-09, R3).
|
||
- [ ] Nach Passwortänderung kommt keine Benachrichtigungs-Mail (AUTH-CFG-19).
|
||
- [ ] SMTP-Anbieter mit AVV und Absender-Domain entschieden und eingerichtet (AUTH-CFG-22, F7).
|
||
- [ ] SPA-Rewrite: `/auth/confirm` wird von der Web-App ausgeliefert.
|
||
- [ ] Rechtstexte-URLs und `TERMS_VERSION` final (R11); Bundle-/Application-ID final (R15).
|
||
|
||
## 6. Bekannte Grenzen
|
||
|
||
- **Keine Drosselung lokal und in der CI-CLI** (A2). Der Drosselungstest läuft gegen einen Extra-Container (Spec D2/T3).
|
||
- **Keine Wartezeit-Angabe:** Die 429-Antwort trägt kein `Retry-After`; die App nennt keine Dauer.
|
||
- **Drosselung nur je IP**, nicht je Konto.
|
||
- **Mail-Limit instanzweit** (30/h): Angreifer können Mailausfälle auslösen. Während der Sperre ist die Existenz eines Kontos über 429 vs. 200 erkennbar (R3, akzeptiert F12).
|
||
- **Enumeration auf API-Ebene:** Signup mit unbestätigter Adresse gibt den echten Nutzer zurück, mit bestätigter einen erfundenen (R6). Die App zeigt in beiden Fällen denselben Bildschirm.
|
||
- **Abgemeldete Geräte nach Reset:** Access-Tokens gelten bis zu 60 min weiter (R8, F1).
|
||
- **Abgebrochene Recovery** bleibt nach einem Reload als normale Anmeldung bestehen (R12).
|
||
- **Häufige Passwörter** prüft nur der Client; der Server erzwingt nur die Länge 10 (R14).
|
||
- **Magic Link / OTP** sind nicht abschaltbar, nur am Gateway sperrbar (R4).
|
||
- **Vorlagen-Rückfall:** Unerreichbare Vorlagen-URL → stille englische Standardvorlage (R5).
|
||
- **Plain-Text-Teil der Mails:** GoTrue sendet nur HTML. Die Vorlagen zeigen den Link deshalb zusätzlich als Klartext; Mailpit erzeugt lokal einen Text-Teil.
|