
# Lokaler Mock-Server

`keenauth mock serve` startet auf Ihrem Rechner einen kleinen OpenID-Connect-, SAML-2.0- und SCIM-2.0-Server sowie eine In-Memory-Version der `/v1`-Management-API, für CI-Jobs ohne Netzwerkzugang und für die lokale Entwicklung. Es braucht keine KeenAuth-Umgebung, keinen API-Schlüssel und kein Internet. Alle Daten liegen im Speicher und werden beim Beenden des Prozesses gelöscht.

Der Mock-Server ist nicht KeenAuth. Er implementiert nur die unten genannten Abläufe, genehmigt jede Anfrage automatisch und prüft deutlich weniger als der echte Dienst. **Ihre gehostete `development`-Umgebung ist die einzige Referenz für das reale Verhalten**: Führen Sie Ihre End-to-End-Tests vor einer Freigabe gegen sie aus.

## Server starten

```sh
keenauth mock serve
```

Standardmäßig lauscht der Server auf `127.0.0.1:4010`, einer Loopback-Adresse, die andere Rechner nicht erreichen können. `--port` ändert den Port (`0` wählt einen freien aus). `--host` ändert die Adresse; jede andere Adresse als eine Loopback-Adresse macht den Mock-Server in Ihrem Netzwerk erreichbar, und die CLI gibt dann eine Warnung aus. Beenden Sie den Server mit Ctrl+C.

Der Befehl liest keine Zugangsdaten und sendet nichts an KeenAuth.

## Endpunkte

| Pfad | Zweck |
|---|---|
| `/.well-known/openid-configuration` | OIDC-Discovery-Dokument (auch unter `/.well-known/oauth-authorization-server` bereitgestellt) |
| `/.well-known/jwks.json` | Öffentlicher Test-Schlüsselsatz (Schlüssel-ID `keenauth-test-1`) |
| `/oauth2/authorize` | Autorisierungsendpunkt: Authorization-Code-Ablauf mit PKCE (`S256`) |
| `/oauth2/token` | Token-Endpunkt: Grants `authorization_code` und `refresh_token` |
| `/oauth2/userinfo` | UserInfo-Endpunkt (Bearer-Access-Token mit dem Scope `openid`) |
| `/saml-idp/<application_id>/metadata` | SAML-2.0-Metadaten des Identity Providers |
| `/saml-idp/<application_id>/sso` | SAML-Single-Sign-on-Endpunkt (HTTP-Redirect- und HTTP-POST-Bindings) |
| `/scim/v2/<directory_id>/…` | SCIM-2.0-Endpunkte: `Users`, `Groups`, `ServiceProviderConfig`, `ResourceTypes`, `Schemas` |
| `/v1/…` | In-Memory-Management-API: jede Operation des OpenAPI-Dokuments der Management-API |

Die Endpunkt-URLs im Discovery-Dokument und in den SAML-Metadaten verweisen auf die lokale Adresse, auf der der Server lauscht. `<application_id>` und `<directory_id>` sind beliebige Namen, die Sie wählen (1–64 Zeichen aus `A-Z`, `a-z`, `0-9`, `-`, `_`); es muss vorher nichts registriert werden.

## So verhält er sich

- **Kein Zustimmungsbildschirm, keine Anmeldeseite.** Jede gültige Autorisierungsanfrage wird sofort für einen festen, fiktiven Testbenutzer genehmigt und mit `code`, `state` und `iss` zurückgeleitet. Die `sub` des Benutzers ist `usr_01m3vnbwg0e8mbe7h7xxp6rmkc`, die E-Mail-Adresse `test.user@example.test` (verifiziert) und der Name `Test User`.
- **Keine registrierten Clients.** Jede `client_id` wird akzeptiert. Client-Secrets werden nicht geprüft. `redirect_uri` muss eine absolute `https`-URI sein oder eine `http`-URI auf einem Loopback-Host (`127.0.0.1`, `[::1]`, `localhost`), ohne Fragment; eine ungültige `redirect_uri` oder eine fehlende `client_id` führt zu einer Fehlerseite statt zu einer Weiterleitung.
- **PKCE ist Pflicht.** `code_challenge` mit `code_challenge_method=S256` muss gesendet werden; `plain` wird abgelehnt. Die Token-Anfrage muss den passenden `code_verifier` senden.
- **Codes sind einmalig verwendbar** und laufen nach 60 Sekunden ab. Ein Code, der ein zweites Mal vorgelegt wird, schlägt mit `invalid_grant` fehl und widerruft jedes Token, das daraus ausgestellt wurde.
- **Tokens.** Das Access-Token ist ein JWT nach RFC 9068 (`typ` `at+jwt`), eine Stunde gültig, mit `sub`, `client_id`, `scope` und einer zufälligen `jti`. Seine Audience ist der `resource`-Parameter der Autorisierungsanfrage oder `https://test.keenauth.invalid/oauth2/userinfo`, wenn keiner gesendet wurde. Mit dem Scope `openid` erhalten Sie zusätzlich ein ID-Token (mit `nonce` und `auth_time`; Claims `email` und `name` mit den Scopes `email` und `profile`). Mit `offline_access` erhalten Sie ein Refresh-Token.
- **Refresh-Tokens rotieren.** Jede Erneuerung liefert ein neues Refresh-Token; ein altes vorzulegen schlägt fehl und widerruft die gesamte Kette. Eine Erneuerung darf den Scope einschränken, aber nicht erweitern.
- **UserInfo** akzeptiert nur Access-Tokens, die dieser Prozess ausgestellt hat, die nicht abgelaufen oder widerrufen sind und den Scope `openid` tragen.

## Tokens und Ihr Verifier

Tokens werden mit dem öffentlichen Test-Schlüssel des [Offline-Testkits](/docs/sdk/testing) signiert und tragen den Issuer `https://test.keenauth.invalid`, nicht die lokale Adresse. Die Top-Level-Domain `.invalid` ist reserviert; ein Produktions-Verifier kann diese Tokens daher nie akzeptieren. Die SDK-Verifier akzeptieren sie nur im Testmodus, den Sie im Testcode ausdrücklich aktivieren.

```go
// Go: accept tokens from the mock server in a test.
v, err := keenauthtest.NewVerifier(verify.Config{Audience: "https://test.keenauth.invalid/oauth2/userinfo"})
if err != nil {
	t.Fatal(err)
}
claims, err := v.VerifyAccessToken(ctx, accessToken, nil)
```

Verwenden Sie denselben Testmodus in TypeScript (`createTestVerifier`) und in Python (`keenauth.testing.verifier`). Generische OIDC-Client-Bibliotheken, die verlangen, dass der `issuer` des Discovery-Dokuments mit der URL übereinstimmt, von der sie es abgerufen haben, lehnen das Discovery-Dokument des Mock-Servers ab; konfigurieren Sie sie mit den Endpunkt-URLs direkt oder testen Sie sie gegen Ihre `development`-Umgebung.

## Beispiel: der vollständige Ablauf mit curl

Das Beispiel benötigt `curl`, `openssl` und `jq`. Starten Sie den Server zuerst in einem anderen Terminal.

```sh
BASE=http://127.0.0.1:4010
REDIRECT=http://127.0.0.1:8080/callback
VERIFIER=$(openssl rand -hex 32)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')

# 1. Authorize: the server answers with a redirect that carries the code.
LOCATION=$(curl -s -o /dev/null -w '%{redirect_url}' --get "$BASE/oauth2/authorize" \
  --data-urlencode response_type=code --data-urlencode client_id=app_local \
  --data-urlencode redirect_uri="$REDIRECT" --data-urlencode 'scope=openid email offline_access' \
  --data-urlencode state=xyz --data-urlencode code_challenge="$CHALLENGE" \
  --data-urlencode code_challenge_method=S256)
CODE=$(printf '%s' "$LOCATION" | sed -E 's/.*[?&]code=([^&]+).*/\1/')

# 2. Exchange the code for tokens.
TOKENS=$(curl -s "$BASE/oauth2/token" -d grant_type=authorization_code -d client_id=app_local \
  --data-urlencode code="$CODE" --data-urlencode redirect_uri="$REDIRECT" -d code_verifier="$VERIFIER")

# 3. Call UserInfo with the access token.
curl -s "$BASE/oauth2/userinfo" -H "Authorization: Bearer $(printf '%s' "$TOKENS" | jq -r .access_token)"

# 4. Refresh.
curl -s "$BASE/oauth2/token" -d grant_type=refresh_token -d client_id=app_local \
  --data-urlencode refresh_token="$(printf '%s' "$TOKENS" | jq -r .refresh_token)"
```

Schritt 3 gibt den Testbenutzer aus:

```json
{"email":"test.user@example.test","email_verified":true,"sub":"usr_01m3vnbwg0e8mbe7h7xxp6rmkc"}
```

## SAML-Identity-Provider

Verwenden Sie den Mock-Server als Identity Provider eines SAML-Service-Providers, den Sie entwickeln: Verweisen Sie den Service Provider auf die Metadaten-URL, melden Sie sich an, und der Mock-Server antwortet mit einer signierten Antwort für den Testbenutzer. Die Pfade folgen dem gehosteten SAML-Identity-Provider, den KeenAuth für eine spätere Version plant.

- **Metadaten.** `GET /saml-idp/<application_id>/metadata` liefert ein `EntityDescriptor` mit der Entity-ID `https://test.keenauth.invalid/saml-idp/<application_id>`, dem Signaturzertifikat, den NameID-Formaten `persistent` und `emailAddress` sowie dem SSO-Endpunkt für beide Bindings. Signierte AuthnRequests sind nicht erforderlich (`WantAuthnRequestsSigned="false"`); eine Signatur der Anfrage wird ignoriert.
- **SSO.** Senden Sie die AuthnRequest mit dem HTTP-Redirect-Binding (`GET`, DEFLATE + Base64 in `SAMLRequest`) oder dem HTTP-POST-Binding (`POST`, Base64). Es gibt keine Anmeldeseite: Eine gültige Anfrage wird sofort für den Testbenutzer genehmigt, und Sie erhalten eine HTML-Seite, die `SAMLResponse` (und Ihren `RelayState`, höchstens 80 Byte) selbstständig an die ACS-URL des Service Providers sendet.
- **Die AuthnRequest muss** `ID`, `Version="2.0"`, `IssueInstant`, ein `saml:Issuer` (die Entity-ID Ihres Service Providers) und `AssertionConsumerServiceURL` enthalten, weil der Mock-Server keine Service Provider registriert hat. Die ACS-URL muss eine absolute `https`-URL oder eine `http`-URL auf einem Loopback-Host sein, ohne Fragment. `ProtocolBinding` muss, falls vorhanden, HTTP-POST sein; `Destination` muss, falls vorhanden, die SSO-URL sein. Jede andere Anfrage erhält `400` und wird nirgendwohin gesendet. DTDs werden abgelehnt.
- **Die Antwort** wird zweimal mit RSA-SHA256 und exklusiver Kanonisierung signiert: die Assertion, dann die gesamte Antwort. `InResponseTo` ist die `ID` Ihrer Anfrage, `Destination` und das `Recipient` der Subject-Bestätigung sind die ACS-URL, die `Audience` ist der `Issuer` Ihrer Anfrage, und die Assertion ist ab der Ausstellung 5 Minuten gültig. Die NameID ist `persistent` (ein stabiler Wert pro Anwendung), sofern die Anfrage nicht `emailAddress` verlangt. Die Attribute sind `email`, `given_name`, `family_name` und `name`.

**Der Signaturschlüssel ist öffentlich.** Er wird aus einer veröffentlichten Bezeichnung abgeleitet, daher kann jeder Antworten signieren, die dieses Zertifikat verifiziert. Sein SHA-256-Fingerabdruck ist `fcc2fc37b9ddb800721283156f9eb26ff1b80f099d996a65650f8cb469a9be81`, und sein Subject enthält `TEST ONLY`. Registrieren Sie ihn nur in Entwicklungs- und Testkonfigurationen Ihres Service Providers, niemals in der Produktion. KeenAuth erzwingt dies für eigene SAML-Verbindungen: In Staging- und Produktionsumgebungen lehnt es diesen Schlüssel und jede Entity-ID unter `.invalid` ab, beim Import von Metadaten oder beim Hinzufügen eines Zertifikats und erneut bei der Anmeldung; Entwicklungsumgebungen akzeptieren sie.

### Beispiel: eine SAML-Anmeldung mit curl

Das Beispiel benötigt `curl` und `openssl`. Starten Sie den Server zuerst in einem anderen Terminal.

```sh
BASE=http://127.0.0.1:4010
APP=app_local
ACS=http://127.0.0.1:8080/saml/acs

# 1. IdP metadata: entity ID, signing certificate and SSO URL for your service provider.
curl -s "$BASE/saml-idp/$APP/metadata" -o idp-metadata.xml

# 2. Send an AuthnRequest with the HTTP-POST binding (base64, no compression).
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
REQUEST=$(printf '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_req1" Version="2.0" IssueInstant="%s" AssertionConsumerServiceURL="%s"><saml:Issuer>https://sp.example.com</saml:Issuer></samlp:AuthnRequest>' "$NOW" "$ACS" | openssl base64 -A)
curl -s "$BASE/saml-idp/$APP/sso" --data-urlencode SAMLRequest="$REQUEST" --data-urlencode RelayState=xyz -o form.html

# 3. The page posts SAMLResponse to the ACS URL by itself; decode it to look at the signed response.
sed -n 's/.*name="SAMLResponse" value="\([^"]*\)".*/\1/p' form.html | openssl base64 -d -A > response.xml
grep -o 'InResponseTo="[^"]*"' response.xml | head -1
```

Der letzte Befehl gibt `InResponseTo="_req1"` aus. Ihr Service Provider prüft `response.xml` gegen das Zertifikat in `idp-metadata.xml`.

## SCIM-2.0-Endpunkte

Verwenden Sie die SCIM-Endpunkte, um einen SCIM-Client zu testen, etwa einen Provisionierungs-Connector oder ein Skript, das Benutzer und Gruppen anlegt, ohne Netzwerk. Jedes `<directory_id>` ist ein eigenes, leeres Verzeichnis, das so lange besteht, wie der Prozess läuft.

- **Authentifizierung.** Jede Anfrage braucht `Authorization: Bearer keenauth-mock-scim-token`. Alles andere erhält `401` mit einer `WWW-Authenticate: Bearer`-Aufforderung. Der Wert ist fest und öffentlich; er ist kein KeenAuth-SCIM-Token.
- **Benutzer und Gruppen.** `POST`, `GET`, `PUT`, `PATCH` und `DELETE` auf `/Users` und `/Groups` (RFC 7644). `userName` und der Gruppen-`displayName` sind Pflichtfelder und im Verzeichnis eindeutig, ohne Berücksichtigung der Groß- und Kleinschreibung; ein Duplikat erhält `409` mit `scimType` `uniqueness`. Gruppenmitglieder müssen Benutzer desselben Verzeichnisses sein. Das Löschen eines Benutzers entfernt ihn aus seinen Gruppen. `password` wird akzeptiert und verworfen.
- **Filter und Seiten.** `filter` unterstützt `eq`, `ne`, `co`, `sw`, `ew` und `pr`, verknüpft mit `and` (zum Beispiel `userName eq "ada@example.test"`), sowie `startIndex` und `count` (höchstens 200). `attributes` und `excludedAttributes` wählen Attribute der obersten Ebene aus. `POST /Users/.search` und `/Groups/.search` nehmen dieselben Parameter im Body entgegen.
- **PATCH** unterstützt `add`, `remove` und `replace` mit Pfaden wie `active`, `name.givenName`, `emails[type eq "work"].value`, `members[value eq "<id>"]` und Attributen der Enterprise-Erweiterung; die Operationen einer Anfrage werden entweder alle oder keine angewendet.
- **Versionen.** Jede Ressource trägt `meta.version` und einen `ETag`-Header (`W/"1"`, `W/"2"`, …). `If-Match` bei `PUT`, `PATCH` und `DELETE` liefert `412`, wenn sich die Version geändert hat; `If-None-Match` bei `GET` liefert `304`.
- **Discovery.** `ServiceProviderConfig`, `ResourceTypes` und `Schemas` beschreiben genau dieses Verhalten. `/Bulk` und `/Me` liefern `501`, wie auch in KeenAuth.

### Beispiel: einen Benutzer mit curl provisionieren

Das Beispiel benötigt `curl` und `jq`. Starten Sie den Server zuerst in einem anderen Terminal.

```sh
SCIM=http://127.0.0.1:4010/scim/v2/dir_local
AUTH='Authorization: Bearer keenauth-mock-scim-token'
CT='Content-Type: application/scim+json'

# 1. Create a user; the response carries the id, meta.version and an ETag header.
USER_ID=$(curl -s "$SCIM/Users" -H "$AUTH" -H "$CT" -d '{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "ada@example.test",
  "name": {"givenName": "Ada", "familyName": "Lovelace"},
  "emails": [{"value": "ada@example.test", "type": "work", "primary": true}]
}' | jq -r .id)

# 2. Find it with a filter.
curl -s -G "$SCIM/Users" -H "$AUTH" --data-urlencode 'filter=userName eq "ada@example.test"' | jq .totalResults

# 3. Deactivate it with PATCH, guarded by the version you read.
curl -s -X PATCH "$SCIM/Users/$USER_ID" -H "$AUTH" -H "$CT" -H 'If-Match: W/"1"' -d '{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [{"op": "replace", "path": "active", "value": false}]
}' | jq -c '{active, version: .meta.version}'

# 4. Create a group with the user as a member, then delete the user.
curl -s "$SCIM/Groups" -H "$AUTH" -H "$CT" -d '{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "displayName": "Engineering",
  "members": [{"value": "'"$USER_ID"'"}]
}' | jq -c '.members[0] | {display, type}'
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE "$SCIM/Users/$USER_ID" -H "$AUTH"
```

Die Befehle geben `1`, `{"active":false,"version":"W/\"2\""}`, `{"display":"ada@example.test","type":"User"}` und `204` aus.

## Management-API (`/v1`)

Verwenden Sie die Management-API-Endpunkte, um Code zu testen, der die KeenAuth-Management-API aufruft (ein SDK, die CLI, ein Deployment-Skript), in CI ohne Netzwerk. Die Pfade sind die gehosteten: Verwenden Sie die Basis-URL `http://127.0.0.1:4010/v1` statt der gehosteten, sonst ändert sich nichts. Die Endpunkte werden aus dem OpenAPI-Dokument der Management-API erzeugt, das in der CLI eingebaut ist, daher beantwortet jede Operation dieser API-Version eine Anfrage.

- **Authentifizierung.** Jede Anfrage braucht `Authorization: Bearer keenauth-mock-management-token`. Alles andere erhält `401` mit einer `WWW-Authenticate: Bearer`-Aufforderung, auch auf unbekannten Pfaden. Der Wert ist fest und öffentlich; er ist kein KeenAuth-Management-Schlüssel.
- **Antworten.** Jede Operation antwortet mit dem Erfolgsstatus, den das Dokument angibt (`200`, `201`, `202`, `204`; die beiden Download-Endpunkte antworten mit `302` und einem `Location`, das nicht auflöst). Der Body ist das `example` der Erfolgsantwort im Dokument oder, solange es keines gibt, das kleinste gültige Beispiel aus dem Antwortschema: nur Pflichtfelder, nullbare Felder `null`, Aufzählungen mit ihrem ersten Wert, Zeichenketten, die ihrem `pattern` entsprechen.
- **Einfacher Zustand.** Eine Sammlung, in der Sie Datensätze anlegen können (`POST /v1/users`, `/v1/organizations`, `/v1/applications`, `/v1/organizations/<org_id>/roles`, …), behält sie: Der angelegte Datensatz wird von `GET` auf seinem eigenen Pfad und in der Liste zurückgegeben, `PATCH` und `PUT` ändern ihn, `DELETE` entfernt ihn zusammen mit allem darunter, und ein Pfad unter einem nicht existierenden Datensatz ist `404`. Bezeichner haben die KeenAuth-Präfixform (`usr_…`, `org_…`, `app_…`) und entsprechen dem Muster im Dokument; wo das Dokument keines angibt, wird das Präfix aus dem Parameternamen abgeleitet. Einstellungen, die es pro Umgebung nur einmal gibt (zum Beispiel `/v1/identity-settings`), behalten, was Sie mit `PATCH` oder `PUT` geschrieben haben. Ressourcen, die sich über die API nicht anlegen lassen (zum Beispiel Sitzungen und Berichte), antworten immer mit dem Beispiel.
- **Listen.** `limit` (1–100, Standard 20), `after` oder `before` mit einem Datensatzbezeichner als Cursor sowie `order` (Standard `desc`, neueste zuerst) funktionieren; die Antwort enthält `list_metadata`. Filter wie `status` werden nicht angewendet.
- **Fehler** sind `application/problem+json`, wie im Dokument, mit `code` und einer `request_id`, die auch im Header `Idp-Request-Id` steht. Ein unbekannter Pfad ist `404 not_found`, eine Methode, die der Pfad nicht hat, ist `405 method_not_allowed` mit einem `Allow`-Header, ein Body, der kein gültiges JSON (oder kein Objekt) ist, ist `400 malformed_request`, ein `Content-Type` ungleich JSON ist `415` bei den Operationen, die ihn auflisten, ein fehlendes Pflichtfeld ist `422 validation_failed` mit `errors[]`, ein Body größer als 1 MiB ist `413`, und ein ungültiges `limit` oder ein ungültiger Cursor ist `400`.

**Was sich von der `development`-Umgebung unterscheidet.** Der Mock-Server prüft nur, dass der Body ein JSON-Objekt mit den Pflichtfeldern ist; Feldformate, Längen, Aufzählungen und Eindeutigkeit werden nicht geprüft, und ein Feld mit falschem Typ wird ignoriert. Er ignoriert `If-Match`, `Idempotency-Key` und die übrigen Header und liefert kein `ETag`. Er prüft keine Berechtigungen, Tarifgrenzen, Kontingente, Ratenlimits oder die Region, maskiert keine personenbezogenen Daten, versendet keine E-Mails, führt keine Jobs aus (ein angenommener Job bleibt so, wie er angelegt wurde) und kennt nur eine Umgebung. Datensätze existieren nur für die Lebensdauer des Prozesses, höchstens 10.000 davon. Verwenden Sie Ihre `development`-Umgebung, um herauszufinden, wie sich die echte API verhält.

### Beispiel: anlegen, lesen, ändern und löschen mit curl

Das Beispiel benötigt `curl` und `jq`. Starten Sie den Server zuerst in einem anderen Terminal.

```sh
API=http://127.0.0.1:4010/v1
AUTH='Authorization: Bearer keenauth-mock-management-token'
CT='Content-Type: application/json'

# 1. Create an organization.
ORG_ID=$(curl -s "$API/organizations" -H "$AUTH" -H "$CT" -d '{"name": "Acme"}' | jq -r .id)

# 2. Read it back and list.
curl -s "$API/organizations/$ORG_ID" -H "$AUTH" | jq -c '{id: (.id | .[0:4]), name}'
curl -s "$API/organizations" -H "$AUTH" | jq -c '{count: (.data | length), list_metadata}'

# 3. Rename it with a merge patch.
curl -s -X PATCH "$API/organizations/$ORG_ID" -H "$AUTH" -H 'Content-Type: application/merge-patch+json' -d '{"name": "Acme Inc"}' | jq -r .name

# 4. Delete it; a second read is a 404 problem.
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE "$API/organizations/$ORG_ID" -H "$AUTH"
curl -s "$API/organizations/$ORG_ID" -H "$AUTH" | jq -c '{status, code}'

# 5. Without the token.
curl -s "$API/organizations" | jq -c '{status, code}'
```

Die Befehle geben `{"id":"org_","name":"Acme"}`, `{"count":1,"list_metadata":{"after":null,"before":null}}`, `Acme Inc`, `204`, `{"status":404,"code":"not_found"}` und `{"status":401,"code":"unauthenticated"}` aus.

## Nicht unterstützt

Es gibt keine Test-Uhr, kein DPoP, PAR, keine Request-Objects, keinen Device-Flow, keine Client Credentials, kein Token Exchange, kein Logout oder Widerruf und keine gehosteten Seiten. Der SAML-Identity-Provider hat kein Single Logout, keine verschlüsselten Assertions, kein Artifact-Binding und keine IdP-initiierte Anmeldung. Die SCIM-Endpunkte haben keine Bulk-Operationen, keine Sortierung, kein `/Me` und keine verschachtelten Gruppen, und der Filter kennt kein `or`, `not`, keine Klammern und kein `gt`/`ge`/`lt`/`le`. Testen Sie diese Funktionen in Ihrer `development`-Umgebung.
