Two Forgejo runbooks plus the Authentik OAuth2 provider guide, mirrored from the iCloud folder into the versioned repo. Runbooks: - forgejo-admin-recovery.md — fallback login when Authentik is down using the local admin-local user (prohibit_login reset via SQL). - forgejo-backup-restore.md — backup format, restore scenarios (full / DB-only / single file), disaster recovery on new host. Guides: - authentik-oauth2-provider.md — reusable template for adding native OIDC integrations in Authentik. First applied for Forgejo, ready to reuse for OpenProject, Nextcloud, Grafana. Includes the important launch-URL gotcha from ADR-0006. Each category folder has a README.md with format conventions and an index of the current documents. Refs OP#1118
8.6 KiB
How-To: OAuth2/OIDC Provider in Authentik einrichten
Stand: 2026-04-11 Erstanwendung: M7.1 — Forgejo OIDC Setup Zielgruppe: AI-Agents und Benjamin — wiederverwendbares Template für künftige OIDC-Integrationen
Wann dieses Pattern nutzen
Wenn eine Applikation OIDC (OpenID Connect) als First-Class-Client unterstützt (z.B. Forgejo, OpenProject, Nextcloud, GitLab, Grafana, Mattermost). In diesem Fall ist nativer OIDC besser als ForwardAuth weil:
- User-Identität (Name, Email, Avatar, Gruppen) kommt direkt in der App an
- Auto-Registration / Account-Linking möglich
- API-Tokens der App bleiben unabhängig
- Migration zu anderer IdP-Software trivial
Für Apps ohne OIDC-Support (oder zu komplex zu integrieren): ForwardAuth via Embedded Outpost — siehe das LocoSoft/n8n Pattern.
Voraussetzungen
- Authentik läuft und ist über
welcome.sdda.euerreichbar - SSH-Zugang
authentik-ssoverfügbar - MCP Tools
authentik_*verfügbar ODER API-Token für akadmin - Die App (z.B. Forgejo) ist bereits live oder zumindest geplant — du brauchst die Redirect URI (meist
https://<app-domain>/user/oauth2/<name>/callbackoder ähnlich)
Schritt 1: Gruppe für Zugangskontrolle (optional aber empfohlen)
Statt "jeder in Authentik" → eigene Gruppe pro App, damit User-Anlage und -Abschaltung granular funktioniert.
# Via MCP Tool
mcp.authentik_create_group(name="<app-slug>-users")
Oder via REST API:
TOKEN=<akadmin-api-token>
curl -X POST 'http://localhost:9000/api/v3/core/groups/' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name": "forgejo-users", "is_superuser": false}'
Notiere die zurückgegebene pk (UUID).
Schritt 2: OAuth2/OpenID Provider anlegen
# Vorbereitung: Flow-IDs und Scope-Mapping-IDs holen
TOKEN=<akadmin-api-token>
# Authorization Flow (Default: explicit consent)
AUTH_FLOW="9f7af462-90cf-44d8-99fa-916f8459ba13"
# Invalidation Flow (für logout)
INVAL_FLOW="697e1b4c-db65-4c21-a458-dd7df2bf51f2"
# Scope Property Mappings (diese sind bei uns fest)
SCOPE_OPENID="f878f335-46dd-4104-8dfb-fe72f21dda22"
SCOPE_PROFILE="04294271-539c-44e6-824a-5ab5c1e4613d"
SCOPE_EMAIL="602c1e0a-0c6d-48ef-bada-97d4c6e45f3c"
# Signing Certificate (RS256 statt HMAC)
CERT="663c97fa-f336-49fe-8809-118d3745547a" # authentik Self-signed
# Eigenes Client Secret generieren
CLIENT_SECRET=$(openssl rand -hex 48)
# Provider anlegen
curl -X POST 'http://localhost:9000/api/v3/providers/oauth2/' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d "{
\"name\": \"<App-Name> OIDC\",
\"authorization_flow\": \"$AUTH_FLOW\",
\"invalidation_flow\": \"$INVAL_FLOW\",
\"client_type\": \"confidential\",
\"client_secret\": \"$CLIENT_SECRET\",
\"access_code_validity\": \"minutes=1\",
\"access_token_validity\": \"hours=24\",
\"refresh_token_validity\": \"days=30\",
\"include_claims_in_id_token\": true,
\"signing_key\": \"$CERT\",
\"sub_mode\": \"user_email\",
\"issuer_mode\": \"per_provider\",
\"redirect_uris\": [
{\"matching_mode\": \"strict\", \"url\": \"<REDIRECT_URI>\"}
],
\"property_mappings\": [
\"$SCOPE_OPENID\",
\"$SCOPE_PROFILE\",
\"$SCOPE_EMAIL\"
]
}"
Die Response enthält:
pk— die ID des Providers (numerisch)client_id— auto-generiert, brauchst du für die App-Configclient_secret— das das du mitgegeben hast (bestätigt)
Notiere client_id und client_secret sofort. Das Secret wird in der Web-UI später maskiert.
Schritt 3: Application anlegen
Die Application verbindet Provider + Namen + Zugangs-Policies.
curl -X POST 'http://localhost:9000/api/v3/core/applications/' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "<App-Name>",
"slug": "<app-slug>",
"provider": <PROVIDER_PK>,
"meta_launch_url": "https://<app-domain>/user/oauth2/<auth-name>",
"meta_description": "<Beschreibung>",
"meta_publisher": "Richter & Zech",
"policy_engine_mode": "any"
}'
Die Response enthält die App-ID (UUID).
Wichtig: Der slug bestimmt die Discovery-URL: https://welcome.sdda.eu/application/o/<slug>/.well-known/openid-configuration
KRITISCH — Silent SSO: meta_launch_url muss auf die OAuth2-Initiate-Route der App zeigen, nicht auf die App-Startseite. Nur so wird beim Klick im Authentik-Dashboard der OIDC-Flow automatisch getriggert ohne dass der User nochmal "Sign in with..." klicken muss. Beispiele:
- Forgejo:
https://code.sdda.eu/user/oauth2/authentik(derauthentikTeil ist der Auth-Source-Name ausforgejo admin auth add-oauth --name) - OpenProject:
https://openproject.sdda.eu/auth/oidc_authentik/callback - Grafana:
https://grafana.sdda.eu/login/generic_oauth - Nextcloud:
https://app.sdda.eu/apps/user_oidc/login/<provider_id>
Wenn man die nackte App-URL setzt (https://code.sdda.eu/), zeigt die App ihre eigene Login-Seite an, und der User muss nochmal klicken. Das ist keine silent SSO — das ist eine Frustration.
Schritt 4: Policy Binding (Gruppen-Zugangskontrolle)
Wenn du in Schritt 1 eine Gruppe angelegt hast:
APP_PK=<uuid-aus-schritt-3>
GROUP_PK=<uuid-aus-schritt-1>
curl -X POST 'http://localhost:9000/api/v3/policies/bindings/' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d "{
\"target\": \"$APP_PK\",
\"group\": \"$GROUP_PK\",
\"enabled\": true,
\"order\": 0,
\"timeout\": 30
}"
Damit können nur Mitglieder der Gruppe die App nutzen. User die nicht drin sind, bekommen beim OIDC-Login "Access Denied".
Schritt 5: User zur Gruppe hinzufügen
# Via MCP
mcp.authentik_add_user_to_group(group_id=<UUID>, user_id=<INT>)
Oder REST:
curl -X POST "http://localhost:9000/api/v3/core/groups/$GROUP_PK/add_user/" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"pk": <USER_ID>}'
Schritt 6: Discovery-URL verifizieren
Bevor du in der App den Provider konfigurierst, check dass Authentik die Discovery-URL korrekt ausliefert:
curl -s 'https://welcome.sdda.eu/application/o/<slug>/.well-known/openid-configuration' | jq .
Erwartete Felder:
issuer— muss mit dem Issuer matchen den die App erwartetauthorization_endpointtoken_endpointuserinfo_endpointjwks_uri
Schritt 7: Client in der App konfigurieren
Je nach App unterschiedlich. Bei Forgejo z.B. via CLI:
docker exec -u git forgejo forgejo admin auth add-oauth \
--name authentik \
--provider openidConnect \
--key "<CLIENT_ID>" \
--secret "<CLIENT_SECRET>" \
--auto-discover-url "https://welcome.sdda.eu/application/o/<slug>/.well-known/openid-configuration" \
--scopes "openid profile email" \
--skip-local-2fa
Bei OpenProject: config/settings.yml oder ENV. Bei Nextcloud: App "user_oidc" installieren, dann UI. Bei Grafana: grafana.ini [auth.generic_oauth]. Immer die App-Docs konsultieren.
Schritt 8: Test-Login
- Browser: App-URL → Login-Button "Sign in with authentik"
- Redirect zu welcome.sdda.eu → Login
- Evtl. Consent-Screen bestätigen
- Redirect zurück → User ist eingeloggt
Gotchas
- Issuer-URL muss public sein (nicht
http://10.0.0.7:9000). JWT-Signatur enthält den Issuer — wenn App und Authentik unterschiedliche Issuer sehen, schlägt die Validation fehl. - Subject-Mode
user_emailfunktioniert gut wenn alle User einzigartige Email-Adressen haben. Bei gemeinsamen Mailboxen (info@ etc.) lieberhashed_user_id. - Include Claims in id_token = true ist wichtig für Apps die
email/nameaus dem id_token lesen statt separaten userinfo-Call. - Strict Redirect URIs: Immer
"matching_mode": "strict", niemals Regex — Security. - Policy Timeout = 30s gibt Authentik Luft bei langsamen LDAP/SCIM-Backends.
Template-Reference
Als konkretes funktionierendes Beispiel für alle oben genannten Schritte siehe:
../Forgejo/adr/0003-native-oidc-not-forwardauth.md- Die Forgejo-
.envauf ai-apps enthält die konkreten Werte - Die Authentik-Admin-UI unter
welcome.sdda.eu/if/admin/#/core/applicationszeigt die "Forgejo" Application als lebendes Beispiel
Nächste Apps die dieses Template nutzen könnten
- OpenProject — hat nativen OIDC-Client, aktuell noch ForwardAuth nicht genutzt
- Nextcloud — braucht
user_oidcApp-Installation - Grafana — falls wir Monitoring einführen
- Mattermost — falls wir Chat einführen
- Potenzielle Migration von n8n und locosoft-hilfe-system von ForwardAuth auf OIDC (großer Eingriff, nicht dringlich)