# Authentik als Identity Provider für Matrix

**Status**: ✅ Deployed (Stage 1 + Stage 2 + Enrollment/Recovery/2FA, Closes Issue #7)  
**Domain**: `auth.axion1337.chat`

## Überblick

Authentik = OIDC Provider für MAS → Zentrales Login + Einladungs-basierte Registrierung.

## Stage 1: Authentik Deployment

**Dateien** (in `apps/authentik/`):
- `namespace.yaml`, `helm-repo.yaml`, `authentik-secret.yaml` (SOPS)
- `authentik.yaml` (HelmRelease v2026.x + embedded Postgres)
- `certificate.yaml`, `ingress.yaml`

**Flux Kustomization**: `clusters/matrix/flux-system/authentik-sync.yaml`

## Deployment-Schritte

1. **DNS A-Record**: `auth.axion1337.chat → 49.13.132.245`
2. **Pods hochfahren**: `kubectl get pods -n authentik -w`
3. **Authentik UI**: `https://auth.axion1337.chat/if/flow/initial-setup/` → Admin-Passwort setzen
4. **OIDC Provider**: Admin UI → OIDC Provider erstellen
5. **Application**: Slug `matrix` (wichtig für Issuer URL!)
6. **Redirect URIs**:
   - `https://account.axion1337.chat/upstream/callback/01KQDJTR1ZVTG8JQ220F5BNBFZ`
   - Post-logout: `https://axion1337.chat`
7. **Client ID + Secret kopieren**

## Stage 2: MAS Integration

1. Decrypt: `sops --decrypt --in-place apps/production/custom-configs/mas-secret.yaml`
2. `upstream_oauth2_config` + `passwords-config` Blöcke hinzufügen
3. Encrypt: `sops --encrypt --in-place ...`
4. Commit & Push
5. **WICHTIG**: `passwords: enabled: false` erst nach OIDC-Test!

## Einladungs-Links

Authentik Admin → Flows & Stages → Invitations → Create

## Enrollment/Recovery/2FA Fix (2026-07-27, Issue #7)

Der `matrix-invitation`-Flow hatte nur 2 von 5 nötigen Stages (kein Write/Password/Login) -
Nutzer wurden nie in Synapse angelegt. Behoben und als Authentik Blueprint
(`apps/authentik/authentik-blueprints.yaml`) deklarativ ins Repo übernommen: vollständiger
`matrix-invitation`-Flow (Invite → Prompt → Write → Password → Login → Redirect), leerer
`matrix-recovery`-Flow ergänzt, `Brand.default_application` gesetzt. 2FA/Passkey-Selbst-
Einrichtung optional (`not_configured_action=skip`) — ⚠️ **gilt seit 2026-08-06 nur noch
für Mitglieder, für Admins ist MFA Pflicht**, siehe unten. Auffindbar über
`axion1337.chat/docs/setup/security.html`. Details: siehe Wiki
[Authentik-OIDC.md](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/wiki/Authentik-OIDC).

**Issue #13 geschlossen (2026-07-29)**: der ursprünglich hier vorgesehene direkte 2FA-Link auf
`account.axion1337.chat/account/` (per MAS Custom-Template-Override) wurde verworfen - live
geprüfte OIDC-Discovery zeigt, dass MAS keine 2FA/Passkey-Deep-Link-Action unterstützt. Jetzt
als Client-seitige Änderung nachgehalten:
[ThreadNet-Web#4](https://rohana.axion1337.de/sorb/ThreadNet-Web/issues/4).

---
**Weitere Details**: Siehe Kapitel 2 in diesem Projekt.

## MFA-Pflicht für Admins (2026-08-06, gitops#57)

**Für Mitglieder bleibt 2FA freiwillig, für die Gruppe `authentik Admins` ist sie Pflicht.**

Umgesetzt als eigener Blueprint `admin-mfa-enforcement.yaml` in
`apps/authentik/authentik-blueprints.yaml`.

### Warum eine zweite Stage statt einer Umstellung

`not_configured_action` hängt an der **Stage**, nicht an der Bindung. Die vorhandene
`default-authentication-mfa-validation` umzustellen hätte deshalb **alle Mitglieder**
getroffen — und wäre zugleich eine Änderung an einem Objekt aus Authentiks eigenem
Blueprint gewesen.

Stattdessen: eine eigene `admin-mfa-validation` auf Ordnung **31**, direkt hinter der
Standard-Stage (30) und vor dem Login (100), eingeschränkt über eine `PolicyBinding`
mit gesetztem `group`. Eine solche Bindung wertet Gruppenmitgliedschaft aus
(`PolicyResult(group.is_member(user))`). **Kein Authentik-Standardobjekt wird
angefasst.**

### Die drei Einstellungen, auf die es ankommt

| Feld | Wert | Warum |
|---|---|---|
| `not_configured_action` | `configure` | führt durch die Einrichtung, statt auszusperren |
| `configuration_stages` | TOTP + WebAuthn | sonst kann `configure` nichts anbieten |
| `last_auth_threshold` | `hours=1` | verhindert die doppelte Abfrage |

⚠️ **`configure`, niemals `deny`.** `deny` weist Admins ohne zweiten Faktor ab — und
danach gibt es keinen Weg zurück außer über den Cluster. `configure` erzwingt
genauso, führt aber durch die Einrichtung.

⚠️ **`last_auth_threshold` ist kein Beiwerk.** Die Standard-Stage auf Ordnung 30
validiert bereits, wer einen Faktor besitzt. Ohne Schwelle (`seconds=0`, der Default)
würde unsere Stage direkt danach ein zweites Mal fragen. Mit `hours=1` überspringt
sie sich, wenn das Gerät gerade benutzt wurde — übrig bleibt genau der Zielfall:
Admin ohne zweiten Faktor.

### Die Falle beim Ändern

**Der Gruppenname ist die ganze Wirkung.** Stimmt er nicht, greift die Regel für
**niemanden** — und wirft dabei keinen Fehler. Das ist schlechter als keine Regel,
weil es sich sicher anfühlt. Wer die Gruppe umbenennt, muss den Blueprint mitziehen.

Prüfen lässt sich die Wirkung nur an einem Konto, das in der Gruppe ist: anmelden und
sehen, ob nach dem Passwort die Einrichtung kommt.
