# Anmeldung über authentik (OIDC) Laufzettel spricht generisches OpenID Connect mit Discovery. Der Anbieter muss also nur einen `/.well-known/openid-configuration`-Endpunkt anbieten — authentik tut das. Ein anderer Anbieter (Keycloak, Entra ID, Zitadel) funktioniert genauso, nur heißen die Menüs anders. ## 1. Provider in authentik anlegen **Anwendungen → Provider → Erstellen → OAuth2/OpenID Provider** | Feld | Wert | |---|---| | Name | `Laufzettel` | | Authorization flow | `default-provider-authorization-explicit-consent` (oder implicit) | | Client type | `Confidential` | | Redirect URIs | `https://laufzettel.example.de/api/auth/oidc/rueckruf` | | Signing Key | ein vorhandener Schlüssel | | Scopes | `openid`, `profile`, `email` und ein Scope, der `groups` liefert | Die Redirect-URI ist `APP_URL` plus `/api/auth/oidc/rueckruf` — exakt so, mit demselben Schema und ohne abschließenden Schrägstrich. Läuft Laufzettel hinter einem Reverse Proxy, ist `APP_URL` die **öffentliche** Adresse, nicht die interne. `Client ID` und `Client Secret` notieren. ## 2. Gruppen in den Token bringen Laufzettel liest die Rolle aus dem Claim `groups`. In authentik gibt es dafür den mitgelieferten Scope-Mapping `authentik default OAuth Mapping: OpenID 'profile'` nicht — du brauchst ein eigenes Mapping: **Anpassung → Property Mappings → Erstellen → Scope Mapping** - Name: `Laufzettel Gruppen` - Scope name: `groups` - Expression: ```python return { "groups": [gruppe.name for gruppe in request.user.ak_groups.all()], } ``` Dieses Mapping beim Provider unter **Advanced protocol settings → Scopes** auswählen. ## 3. Anwendung anlegen **Anwendungen → Anwendungen → Erstellen**, den Provider zuordnen, Slug z. B. `laufzettel`. Über die Anwendung steuerst du per Policy, wer sich überhaupt anmelden darf. ## 4. Gruppen für die Rollen Lege in authentik vier Gruppen an und trage die Mitglieder ein: | Gruppe | Rolle in Laufzettel | Darf | |---|---|---| | `lz-admin` | `ADMIN` | alles, inkl. Benutzer, Verzeichnis, Abteilungen, Archiv-Verwaltung | | `lz-redakteur` | `REDAKTEUR` | Vorlagen anlegen, bearbeiten, veröffentlichen | | `lz-techniker` | `TECHNIKER` | Läufe starten, abarbeiten, abschließen, archivieren; Geräte pflegen | | `lz-leser` | `LESER` | nur lesen | | *(keine davon)* | `MITARBEITER` | **nur die eigenen Geräte**, siehe unten | Ist jemand in mehreren Gruppen, gewinnt die stärkere Rolle. > **Die fünfte Zeile hat keine Gruppe, und das ist Absicht.** Wer sich anmeldet und in keiner der > vier Gruppen steht, ist für Laufzettel ein Mitarbeiter des Hauses und bekommt die > Selbstauskunft — vorausgesetzt, er lässt sich einer Person im Verzeichnis zuordnen. Eine eigene > Gruppe dafür anzulegen hieße, jeden Mitarbeiter einzeln einzutragen; „alle übrigen“ ist genau die > Menge, die gemeint ist. ## 5. Laufzettel konfigurieren In der `.env`: ```dotenv APP_URL=https://laufzettel.example.de OIDC_ISSUER=https://authentik.example.de/application/o/laufzettel/ OIDC_CLIENT_ID=... OIDC_CLIENT_SECRET=... OIDC_NAME=authentik OIDC_GROUP_ADMIN=lz-admin OIDC_GROUP_EDITOR=lz-redakteur OIDC_GROUP_TECHNICIAN=lz-techniker OIDC_GROUP_VIEWER=lz-leser ``` Den `OIDC_ISSUER` zeigt authentik beim Provider unter **OpenID Configuration Issuer** an. Der abschließende Schrägstrich gehört dazu. Danach neu starten: ```bash docker compose up -d ``` ## 6. Was beim Login passiert - Ein unbekannter Benutzer wird beim ersten Login **angelegt** (JIT-Provisioning) - Die Rolle wird bei **jedem** Login aus `groups` neu gesetzt — eine Änderung in authentik greift ab der nächsten Anmeldung - Ist der Benutzer in keiner der vier Gruppen, versucht Laufzettel, ihn über seinen **UPN** einer Person im Verzeichnis zuzuordnen. Klappt das, bekommt er `MITARBEITER` und sieht nur seine eigenen Geräte; klappt es nicht, wird die Anmeldung **abgewiesen** — mit einer Begründung auf der Anmeldeseite - **Bis Version 0.2.0 bekam er stattdessen `LESER`**, also Lesezugriff auf alle Läufe des Hauses. Wer das Verhalten von damals braucht, trägt die betreffenden Leute in `lz-leser` ein - Wer vor dem Login eine bestimmte Seite aufgerufen hat (z. B. `/t/LZ-7K3F9Q` nach dem Scannen eines QR-Codes), landet danach genau dort ## 7. Selbstauskunft für Mitarbeiter Ein Mitarbeiter, der in keiner Rollengruppe steht, sieht unter **Meine Geräte** die Arbeiten an seinen eigenen Geräten — Titel, Zeitraum, Status. **Keine Schritte, keine Notizen, keine Kommentare, keine Anhänge**; warum, steht in `docs/architektur.md` unter „Warum ein Mitarbeiter keine Akteneinsicht bekommt“. Zugeordnet wird über den **UPN**. Laufzettel liest ihn in dieser Reihenfolge: 1. der Anspruch `upn` (so heißt er bei Entra ID) 2. `preferred_username` (authentik und Keycloak schicken dort den Anmeldenamen) 3. die Mailadresse Verglichen wird mit `Mitarbeiter.upn`, unabhängig von Groß- und Kleinschreibung. Damit das greift, muss der UPN in authentik derselbe sein wie der im Active Directory — bei einem AD als Quelle von authentik ist er das meist von selbst. **Zwei Fälle, die bewusst nicht durchgehen:** | Fall | Was passiert | |---|---| | Zu dem UPN gibt es **keine aktive** Person | Anmeldung abgewiesen, mit Begründung auf der Anmeldeseite | | Zu dem UPN gibt es **mehr als eine** Person | Anmeldung abgewiesen und im Protokoll festgehalten | Der zweite Fall kommt im Modus **Dienstleistung** vor, wenn zwei Kunden dieselbe Person führen. Ein Zufallstreffer wäre dort schlimmer als kein Zugang: er entschiede nach Sortierung darüber, wessen Geräte jemand sieht. **Abschalten lässt sich das Ganze**, indem du keine Rollengruppen konfigurierst — dann greift die Weiche nicht, und alles bleibt wie vor 0.2.0. Oder indem du jeden, der hinein soll, in `lz-leser` einträgst. ## 8. Notfallzugang Fällt authentik aus, kommt niemand mehr in Laufzettel. Für diesen Fall gibt es den lokalen Login: ```dotenv AUTH_LOCAL_ENABLED=true ``` Er ist standardmäßig **aus**. Ein lokales Admin-Konto legst du über den Seed an (`SEED_ADMIN_EMAIL`, `SEED_ADMIN_PASSWORD`) oder als Admin unter **Admin → Benutzer**. Die Passwörter liegen als argon2-Hash in der Datenbank. Empfehlung: ein einziges lokales Admin-Konto, Passwort im Passwortmanager, `AUTH_LOCAL_ENABLED` im Normalbetrieb auf `false` und nur im Notfall umgestellt. ## 9. Fehlersuche | Symptom | Ursache | |---|---| | `redirect_uri_mismatch` | Die URI in authentik stimmt nicht zeichengenau mit `APP_URL` + `/api/auth/oidc/rueckruf` überein — oft `http` gegen `https` oder ein abschließender Schrägstrich | | Nach dem Login wieder auf der Anmeldeseite | Das Cookie ist `Secure`, die Verbindung aber `http`. Entweder HTTPS nutzen oder zum Testen über `localhost` gehen | | Jeder bekommt `LESER` | Der Claim `groups` fehlt im Token. Scope-Mapping aus Schritt 2 angelegt und beim Provider ausgewählt? | | Discovery schlägt fehl | `OIDC_ISSUER` falsch oder von der App aus nicht erreichbar. Im Compose-Stand hängt `web` im Netz `extern` — prüfen, ob der Name auflösbar ist |