Zum Hauptinhalt springen

OIDC-Single-Sign-on

fremforge unterstützt OpenID Connect (OIDC) für Single Sign-on. OIDC ist das Single-Sign-on-Protokoll, das fremforge unterstützt. Alle großen IdPs (Entra, Okta, Google Workspace, Auth0, Authentik, Keycloak) bringen OIDC von Haus aus mit. Der Lebenszyklus der Signaturschlüssel läuft automatisch über die OIDC-Discovery- und JWKS-Endpunkte.

OIDC ist derzeit das einzige Single-Sign-on-Protokoll, das fremforge anbietet. SAML ist noch nicht verfügbar; Microsoft Entra ID und ADFS unterstützen beide OIDC.

Einrichtung

Schritt 1: eine Domain verifizieren

Organisationsverwaltung → SSO → Verifizierte Domains (den eingeklappten Abschnitt aufklappen) → füge deine E-Mail-Domain hinzu (z. B. acme.com). Weise die Kontrolle über die Domain auf einem dieser Wege nach:

  • DNS-TXT-Eintrag: Füge _fremforge-verification=<token> im DNS deiner Domain hinzu und klicke dann auf Verify.
  • HTTP-Datei: Stelle das Token unter https://acme.com/.well-known/fremforge-verification bereit und klicke dann auf Verify.

Die Domain-Verifizierung ist Voraussetzung, bevor du eine Auth-Quelle registrieren kannst. Du erledigst sie nur einmal.

Schritt 2: eine OAuth-2.0-Anwendung in deinem IdP anlegen

fremforge braucht drei Werte von deinem IdP: Client ID, Client Secret und die Aussteller-URL (auch Wurzel der OIDC-Discovery-URL genannt). Konfiguriere deinen IdP wie folgt.

Okta

  1. Applications → Create App Integration → OIDC, Web Application.
  2. Sign-in redirect URIs: https://frem.sh/user/oauth2/<auth-source-name>/callback
  3. Sign-out redirect URIs: https://frem.sh/<your-org>/logout (optional, aber empfohlen)
  4. Assignments: Weise die Anwendung den Gruppen oder Nutzern zu, die Zugriff auf fremforge haben sollen.
  5. Kopiere Client ID, Client Secret und die Okta domain (z. B. https://acme.okta.com).
    • Aussteller-URL = https://acme.okta.com (oder https://acme.okta.com/oauth2/default bei eigenen Autorisierungsservern)

Microsoft Entra (Azure AD)

  1. App registrations → New registration, Name „fremforge“, unterstützte Kontotypen = Single-Tenant.
  2. Redirect URI: Web → https://frem.sh/user/oauth2/<auth-source-name>/callback
  3. Certificates & secrets → New client secret, kopiere den Value sofort (er wird nur einmal angezeigt).
  4. Overview: Kopiere die Application (client) ID und die Directory (tenant) ID.
    • Aussteller-URL = https://login.microsoftonline.com/<tenant-id>/v2.0
  5. Token configuration → Add groups claim, wähle Security groups. Damit wird der groups-Claim befüllt, den fremforge für die Zuordnung zu Teams nutzt.
  6. API permissions: Prüfe, dass openid, profile und email gewährt sind (standardmäßig der Fall).

ADFS

ADFS ab Windows Server 2016 ist ein OpenID-Connect-Anbieter.

  1. AD FS Management → Application Groups → Add Application Group, Name „fremforge“, Vorlage Server application (unter Standalone applications) oder Server application accessing a web API.
  2. Kopiere den Client Identifier. Redirect URI: https://frem.sh/user/oauth2/<auth-source-name>/callback.
  3. Configure Application Credentials → Generate a shared secret, kopiere es (es wird nur einmal angezeigt).
  4. Gewähre die Scopes openid, profile und email und füge Ausstellungs-Transformationsregeln hinzu, die email und name (und einen Gruppen-Claim, falls du Teams zuordnest) in das ID-Token schreiben.
    • Aussteller-URL = https://<your-adfs-host>/adfs (Discovery unter https://<your-adfs-host>/adfs/.well-known/openid-configuration)

Die OIDC-MFA-Prüfung wurde noch nicht mit ADFS getestet. Schalte sie zuerst für einen einzelnen Testnutzer ein und prüfe, ob die Anmeldung gelingt.

Google Workspace

  1. Google Cloud Console → APIs & Services → Credentials → Create credentials → OAuth client ID.
  2. Anwendungstyp: Web application.
  3. Authorised redirect URIs: https://frem.sh/user/oauth2/<auth-source-name>/callback
  4. Kopiere Client ID und Client Secret.
    • Aussteller-URL = https://accounts.google.com
  5. Beschränke unter Google Workspace Admin → Security → API controls → Domain-wide delegation die OAuth-Einwilligung auf deine Domain, damit sich nur Mitglieder deines Workspace authentifizieren können.

Authentik

  1. Applications → Providers → Create → OAuth2/OpenID Connect Provider.
  2. Redirect URIs: https://frem.sh/user/oauth2/<auth-source-name>/callback
  3. Signing Key: Wähle dein Authentik-Signaturzertifikat.
  4. Kopiere Client ID, Client Secret und die OpenID Configuration URL (entferne /.well-known/openid-configuration; die Aussteller-URL ist die Wurzel, z. B. https://sso.acme.internal/application/o/<slug>/).
  5. Lege eine Application an und verknüpfe sie mit dem Provider; setze die Launch-URL auf frem.sh/user/login?redirect_to=/<your-org>.

Keycloak

  1. Your Realm → Clients → Create client.
  2. Client type: OpenID Connect. Client ID: fremforge.
  3. Valid redirect URIs: https://frem.sh/user/oauth2/<auth-source-name>/callback
  4. Reiter Credentials: Kopiere das Client Secret.
    • Aussteller-URL = https://keycloak.acme.internal/realms/<your-realm>

Auth0 / Okta Customer Identity Cloud

  1. Applications → Create Application → Regular Web Application.
  2. Allowed Callback URLs: https://frem.sh/user/oauth2/<auth-source-name>/callback
  3. Allowed Logout URLs: https://frem.sh/<your-org>/logout
  4. Settings: Kopiere Domain, Client ID und Client Secret.
    • Aussteller-URL = https://<your-auth0-domain>/

Schritt 3: den Anbieter in fremforge registrieren

  1. Organisationsverwaltung → SSO, scrolle zu Neue SSO-Quelle hinzufügen und klicke auf Start wizard (öffnet /_admin/sso/wizard/start).
  2. Wähle OpenID Connect als Quelltyp und fahre fort.
  3. Fülle aus:
    • Anzeigename: Er erscheint auf der Schaltfläche der Anmeldeseite, z. B. „Mit Okta anmelden“.
    • Client ID und Client Secret aus Schritt 2.
    • Aussteller-URL: fremforge ruft <issuer>/.well-known/openid-configuration ab und ermittelt die Endpunkte automatisch.
  4. Attribute mapping (für die meisten IdPs reichen die optionalen Standardwerte):
    • Claim email → E-Mail in fremforge (Standard: email)
    • Claim username → Forgejo-Benutzername (Standard: preferred_username → ersatzweise email)
    • Claim display_name → vollständiger Name (Standard: name)
  5. Gehe die Prüf- und Bestätigungsschritte des Assistenten durch. fremforge führt einen Discovery-Abruf aus und prüft die Verbindung, bevor gespeichert wird.

Nach dem Speichern erscheint auf der Anmeldeseite deiner Organisation unter frem.sh/user/login?redirect_to=/<your-org> eine Schaltfläche Anmelden mit <name>.

Über die REST-API

Die OIDC-Auth-Quelle lässt sich auch programmatisch registrieren – nützlich, wenn du die Bereitstellung von Organisationen skriptest oder die Einrichtung aus CI steuerst. Dabei läuft dieselbe Funktion provisionOidcAuthSource wie im Admin-Assistenten.

  • Zuerst eine Domain verifizieren POST /_app/api/v1/orgs/:slug/sso/domains mit dem Body { "domain": "acme.com" }, danach POST /_app/api/v1/orgs/:slug/sso/domains/:id/verify
  • Die OIDC-Quelle registrieren POST /_app/api/v1/orgs/:slug/sso, der Body enthält type: "oidc", issuer_url, client_id, client_secret
  • Zuordnung Gruppe→Team aktualisieren PUT /_app/api/v1/orgs/:slug/sso mit dem Body { "id": "...", "group_team_map": { ... } }
  • Quellen auflisten GET /_app/api/v1/orgs/:slug/sso

Erfordert ein Personal Access Token (PAT) mit dem Scope sso:write:

curl -X POST \
  -H "Authorization: Bearer ${FREMFORGE_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-okta",
    "type": "oidc",
    "issuer_url": "https://acme.okta.com",
    "client_id": "0oa1abc...",
    "client_secret": "s3cr3t..."
  }' \
  https://frem.sh/_app/api/v1/orgs/acme/sso

Die vollständige OpenAPI-Spezifikation findest du in der Referenz der öffentlichen REST-API.

Was bei der Anmeldung passiert

  1. Die Person klickt unter frem.sh/user/login?redirect_to=/<your-org> auf Anmelden mit <name>.
  2. fremforge leitet mit scope=openid email profile zum Autorisierungsendpunkt deines IdP weiter.
  3. Die Person authentifiziert sich beim IdP (MFA erzwingt der IdP, nicht fremforge).
  4. Der IdP leitet mit einem Autorisierungscode zurück nach frem.sh/user/oauth2/<auth-source-name>/callback.
  5. fremforge tauscht den Code gegen Tokens, prüft die Signatur des ID-Tokens gegen das JWKS des IdP, liest die Claims für E-Mail und Benutzername aus und legt den Forgejo-Benutzer an oder aktualisiert ihn.
  6. Ist Require SSO aktiviert (Organisationsverwaltung → SSO → Richtlinien), ist die direkte Anmeldung mit Passwort gesperrt. Nur der Weg über den IdP funktioniert.

SSO erzwingen

Organisationsverwaltung → SSO → Richtlinien → Require SSO for all members. Nach dem Aktivieren gilt:

  • Bestehende Mitglieder müssen sich bei der nächsten Anmeldung über den IdP neu authentifizieren.
  • PATs und SSH-Schlüssel bleiben als Authentifizierungsmittel gültig, aber mit aktiviertem Require SSO wird die IdP-Sitzung bei Git-Operationen alle 15 Minuten neu geprüft. Wer im IdP deaktiviert wird, verliert daher innerhalb von 15 Minuten den Push-/Pull-Zugriff, auch wenn sein SSH-Schlüssel noch registriert ist. Ein separates Widerrufen der Schlüssel ist nicht nötig.
  • Neue Einladungen von Mitgliedern führen zu reinen SSO-Konten.

Mit SCIM für den vollständigen Lebenszyklus kombinieren

OIDC übernimmt die Authentifizierung. Um die Bereitstellung und Deprovisionierung von Nutzern zu automatisieren (Konten bei Einstellung anlegen, bei Austritt deaktivieren, Gruppenmitgliedschaften synchronisieren), kombiniere OIDC mit der SCIM-2.0-Bereitstellung.

Die meisten Unternehmens-IdPs (Okta, Entra) unterstützen OIDC und SCIM gleichzeitig. Die typische Einrichtung:

  1. OIDC konfigurieren, damit sich Mitglieder über den IdP anmelden können.
  2. SCIM aktivieren, damit der IdP Änderungen an Nutzern und Gruppen automatisch überträgt.
  3. Require SSO aktivieren. Mit aktivem SCIM sperrt die Deprovisionierung im IdP den Zugriff auf fremforge sofort.

Rotation der Schlüssel

fremforge speichert das JWKS (die Signaturschlüssel) des IdP zwischen und aktualisiert es nach Zeitplan sowie bei einer fehlgeschlagenen Signaturprüfung. Eine Schlüsselrotation auf IdP-Seite (z. B. die automatische Schlüsselrotation von Okta) wird transparent verarbeitet. Du musst nichts tun.

Wenn du das Client Secret im IdP rotierst:

Die Karte der Auth-Quelle unter Organisationsverwaltung → SSO hat kein Feld für das Client Secret, und eine Auth-Quelle lässt sich nach dem Anlegen nicht mehr bearbeiten. Um das Secret zu ändern, wende dich an support@frem.sh, bevor du das alte im IdP widerrufst: Wir aktualisieren es für dich, und die Anmeldung funktioniert weiter.

OIDC deaktivieren

Um die Anmeldung über OIDC zu beenden, entferne die Auth-Quelle: Organisationsverwaltung → SSO → <Auth-Quelle> → Entfernen. Die Anmeldung darüber endet sofort. Hat sich noch kein Mitglied darüber angemeldet, wird sie gelöscht; andernfalls behält fremforge eine abgeschaltete, umbenannte Kopie, damit die Konten erhalten bleiben. Konten, Sitzungen und Zugriffstoken dieser Mitglieder werden nicht widerrufen: Um diesen Zugriff zu beenden, entferne die Mitglieder aus der Organisation oder deprovisioniere sie über SCIM. Wer nur den OIDC-Weg hatte, fällt auf E-Mail und Passwort zurück (wenn ein lokales Passwort gesetzt ist) oder kann sich nicht mehr anmelden; stelle also vorher sicher, dass sich ein Break-Glass-Owner noch mit einem lokalen Passwort anmelden kann. Schlägt das Entfernen fehl, sagt die Konsole das, es ändert sich nichts und die Anmeldung über die Quelle funktioniert weiter.

Es gibt keinen Schalter, der eine Auth-Quelle vorübergehend ab- und später wieder einschaltet; wende dich dafür an support@frem.sh. Damit keine verwaisten Konten entstehen, entferne die Auth-Quelle, bevor du die Anwendung in deinem IdP abbaust, nicht danach.

Fehlerbehebung

Redirect-URI stimmt nicht überein

Der IdP lehnt den Callback ab, wenn die im IdP registrierte Redirect-URI nicht exakt https://frem.sh/user/oauth2/<auth-source-name>/callback entspricht. <auth-source-name> ist der Name, den du beim Hinzufügen der Auth-Quelle in fremforge vergeben hast (z. B. okta-primary, entra-prod); der OAuth2-Router von Forgejo verteilt den Callback anhand dieses Namens. Kopiere die exakte Callback-URL aus dem Feld Redirect URI, das der SSO-Assistent beim Hinzufügen der Auth-Quelle anzeigt (Organisationsverwaltung → SSO → + SSO-Quelle hinzufügen), statt sie abzutippen; bei der URL zählen Groß- und Kleinschreibung und abschließende Schrägstriche.

invalid_client beim Token-Austausch

Client ID oder Client Secret ist falsch. Kopiere sie erneut aus der IdP-Konsole. Manche IdPs zeigen das Secret nur einmal beim Anlegen an. Erzeuge ein neues Secret, wenn du das ursprüngliche nicht gesichert hast.

Claims fehlen (Benutzername oder E-Mail leer)

Prüfe die Richtlinie deines IdP für die Freigabe von Attributen und Claims. fremforge benötigt mindestens den Claim email im ID-Token. Wenn dein IdP die Freigabe von Claims an ausdrückliche Berechtigungen knüpft (Entra verlangt z. B. die API-Berechtigungen profile und email), stelle sicher, dass sie gewährt und bestätigt sind.

Nutzer bereitgestellt, aber Anmeldung schlägt fehl

Ist Require SSO aktiviert und passt die E-Mail-Domain der Person zu keiner verifizierten Domain, blockiert fremforge die Anmeldung. Verifiziere die Domain unter Organisationsverwaltung → SSO → Verifizierte Domains. Die Domain im Claim email der Person muss übereinstimmen.

Step-up mit Sitzungsbindung pro Organisation

Über die normale SSO-Anmeldung hinaus kann fremforge jedes Mal eine frische, vom IdP bestätigte Authentifizierung erzwingen, wenn jemand in den Verwaltungsbereich einer anderen Organisation wechselt. Das ist die auf der Preisseite zugesagte „Sitzungsbindung pro Organisation“ in der Stärke für regulierte Branchen – nützlich, wenn jede organisationsübergreifende Verwaltungsaktion eine vom IdP bestätigte Authentifizierung für genau diese Organisation tragen muss.

Es gibt zwei Stärkestufen. Die Bindung ist standardmäßig aktiv; welche Stufe gilt, hängt davon ab, ob du den unten beschriebenen Step-up-Client einrichtest:

  • Weiche Bindung (Standard, wenn du keinen Step-up einrichtest): Die Umleitung beim ersten Zugriff auf eine andere Organisation läuft über Forgejos universelles /user/login. Ist deine Forgejo-Sitzung aktuell, ist der Umweg unsichtbar und fragt nichts ab. Er beweist also, dass der Browser eine gültige Sitzung hat, nicht, dass sich die Person erneut authentifiziert hat. Nutze die harte Bindung, wenn du pro Organisation eine frische Authentifizierung brauchst. Der Break-Glass-Zugang mit lokalen Anmeldedaten bleibt erhalten.
  • Harte Bindung (siehe Einrichtung unten): Die Umleitung läuft über den Step-up-Endpunkt von fremforge, der bei deinem IdP eine OIDC-Authentifizierung mit prompt=login startet. Der IdP MUSS erneut nach Anmeldedaten und MFA fragen; wir prüfen, dass auth_time im zurückgegebenen ID-Token höchstens 5 Minuten alt ist. Der Break-Glass-Zugang mit lokalen Anmeldedaten über /user/login funktioniert für Owner der Organisation weiterhin; die harte Bindung ändert nur den Weg beim organisationsübergreifenden Zugriff, nicht die universelle Anmeldung.

Harte Bindung einrichten

Die harte Bindung erfordert einen ZWEITEN OIDC-Client in deinem IdP neben dem, den Forgejo nutzt (gleicher Aussteller, eigene client_id und eigenes client_secret, eigene Redirect-URI).

  1. Registriere in deinem IdP eine neue OIDC-Anwendung:

    FeldWert
    AnwendungstypWeb (vertraulich)
    Grant-TypenAuthorization Code, mit PKCE
    Redirect-URIhttps://frem.sh/<your-org>/_admin/-/stepup/callback
    Authentifizierungsmethode am Token-Endpunktclient_secret_basic oder client_secret_post
    Erforderliche Scopesopenid, email
    Claim auth_timeIm ID-Token erforderlich
    prompt=loginWird beachtet (Standardverhalten der meisten IdPs)
  2. Gehe in fremforge zu Organisationsverwaltung → SSO, klappe Add OIDC auth source auf und fülle unten im Formular die optionalen Felder unter Per-org session-binding step-up aus:

    • Step-up Client ID: aus der neuen App in deinem IdP
    • Step-up Client Secret: aus der neuen App in deinem IdP; wird vor dem Speichern mit AES-256-GCM (Unterschlüssel per HKDF abgeleitet) verschlüsselt abgelegt
    • Step-up Redirect URI: https://frem.sh/<your-org>/_admin/-/stepup/callback
  3. Prüfen: Öffne https://frem.sh/<your-org>/_admin/billing in einem neuen Browserfenster. Du solltest über deinen IdP umgeleitet werden, erneut zur Anmeldung aufgefordert werden und wieder auf der Abrechnungsseite landen. Das Audit-Log zeigt ein Ereignis org-session.step-up.ok mit auth_time.

Bleiben die Step-up-Felder leer, fällt die Auth-Quelle auf die weiche Bindung zurück – nützlich für Organisationen, die SSO bei der Anmeldung wollen, aber keine IdP-Bestätigung pro Organisation brauchen.

Fehlerbehebung bei der harten Bindung

  • „IdP did not emit auth_time“: Der IdP hat ein ID-Token ohne den Claim auth_time zurückgegeben. fremforge braucht ihn, weil wir daran prüfen, wie frisch die erneute Authentifizierung ist. Prüfe die Claim-Richtlinie des IdP; die meisten haben eine Option wie „include auth_time“.
  • „auth_time too old“: Der IdP hat prompt=login auf Protokollebene akzeptiert, die Person aber nicht tatsächlich erneut abgefragt. Verschärfe die Richtlinie für „Session Lifetime“ oder „Max Age“ des IdP für diesen Client.
  • „step-up cookie binding mismatch“: Die Person hat mitten im Ablauf die Identität gewechselt (z. B. einen zweiten Browser-Tab geöffnet und sich als andere Person angemeldet). Beginne erneut bei /<your-org>/_admin/billing.
  • „step-up redirect URI rejected“: Die URI hat unsere Prüfung auf öffentliches HTTPS nicht bestanden (private, Loopback- und Metadaten-Adressen sind gesperrt). Verwende die kanonische Form frem.sh/_app.

Querverweise