
# Anwendung erstellen

`POST /v1/applications` · Berechtigung `applications:write`

Erstellt eine Anwendung (einen OAuth/OIDC-Client) in der Umgebung des aufrufenden Schlüssels. `key`, `name`, `app_type` und `party` sind erforderlich; jedes andere Feld erhält einen sicheren Standardwert, der vom Anwendungstyp abgeleitet wird. Die Antwort enthält einen `ETag`, den Sie beim Aktualisieren oder Löschen als `If-Match` senden. Dieser Vorgang erstellt kein Client-Secret; Secrets und Schlüssel werden über die Endpunkte für Anwendungsanmeldedaten verwaltet.

## Anfrage

**Body** (`application/json`). Unbekannte Felder werden abgelehnt. Nur `key`, `name`, `app_type` und `party` sind erforderlich.

| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
| `key` | string | ja | Stabiler Konfigurationsschlüssel, `^[a-z0-9_-]{1,64}$`, pro Umgebung eindeutig. Beim Erstellen erforderlich; danach nicht änderbar. |
| `name` | string | ja | Anzeigename, 1–100 Zeichen. |
| `app_type` | string | ja | `web`, `spa`, `native`, `m2m`, `device` oder `management`. Beim Erstellen erforderlich; danach nicht änderbar. |
| `party` | string | ja | `first_party` oder `third_party`. Beim Erstellen erforderlich; kann nur von `first_party` zu `third_party` geändert werden. |
| `owner_org_id` | string or null | nein | `org_…`-ID der besitzenden Organisation; nur für `m2m`-Anwendungen; nicht änderbar. |
| `status` | string | nein | `active` oder `suspended`. Eine gesperrte Anwendung kann keine neuen Tokens erhalten. |
| `allowed_web_origins` | string[] | nein | Erlaubte CORS-Ursprünge (`https://host[:port]`), höchstens 20, keine Wildcards. |
| `organization_usage` | string | nein | `deny`, `allow` oder `require`. Steuert den Autorisierungsparameter `organization` (eine `org_…`-ID oder der Slug der Organisation): `deny` lehnt ihn ab, `allow` macht ihn optional, `require` macht ihn verpflichtend. Das Token enthält `org_id` erst, nachdem die Mitgliedschaft des Benutzers geprüft wurde. |
| `org_access_mode` | string | nein | Zugriffsmodus für die Anmeldung über Organisationen: `all_organizations` (Standard; jedes Mitglied jeder Organisation), `enabled_organizations` (nur Organisationen, in denen die Anwendung aktiviert ist) oder `assigned_only` (zusätzlich nur zugewiesene Mitgliedschaften oder Verzeichnisgruppen). Siehe [Organisationsanwendungen](../organization-applications/get.md). |
| `registration_mode` | string or null | nein | `open`, `invite_only` oder `closed`; leer übernimmt die Einstellung der Umgebung. |
| `registration_source` | string | nein | `dashboard` oder `management_api` beim Erstellen (Standard `management_api`); nicht änderbar. Antworten können auch `dcr` oder `cimd` anzeigen. |
| `verification_status` | string | nein | `verified` oder `unverified`. |
| `security_profile` | string | nein | `baseline` (derzeit das einzige beschreibbare Profil). |
| `token_endpoint_auth_method` | string | nein | `private_key_jwt`, `client_secret_basic`, `client_secret_post` oder `none`; muss für den `app_type` erlaubt sein. |
| `grant_types` | string[] | nein | Erlaubte Grant-Typen; eine Teilmenge dessen, was der `app_type` zulässt. |
| `default_api_id` | string or null | nein | `api_…`-ID der API, die verwendet wird, wenn eine Anfrage kein `resource` enthält. |
| `require_par` | boolean | nein | Verlangt Pushed Authorization Requests. |
| `require_state` | boolean | nein | Verlangt `state`. |
| `require_nonce` | boolean | nein | Verlangt `nonce`. |
| `pkce_required` | boolean | nein | Verlangt PKCE; kann nur für eine vertrauliche Webanwendung deaktiviert werden. Ohne PKCE ist `nonce` die einzige Verteidigung gegen Authorization-Code-Injection, daher muss `require_nonce` außerhalb von Entwicklungsumgebungen aktiviert bleiben (andernfalls `validation_failed` auf `/require_nonce`). |
| `skip_consent` | boolean | nein | Überspringt den Zustimmungsbildschirm; nur für Erstanbieter-Anwendungen. |
| `token_binding_policy` | string | nein | `none` oder `dpop_required`. |
| `login_host` | string or null | nein | Einer der Login-Hosts der Umgebung (DNS-Name in Kleinbuchstaben). |
| `default_max_age_s` | integer or null | nein | Standardwert für `max_age` in Sekunden. |
| `min_acr` | string or null | nein | Mindestens erforderliche Authentifizierungssicherheit: `urn:idp:acr:1fa`, `urn:idp:acr:mfa` oder `urn:idp:acr:phr`. |
| `access_token_lifetime_s` | integer or null | nein | Gültigkeitsdauer des Access-Tokens, 60–86400 Sekunden. |
| `refresh_idle_s` | integer or null | nein | Inaktivitätsdauer des Refresh-Tokens in Sekunden; nicht größer als `refresh_absolute_s`. |
| `refresh_absolute_s` | integer or null | nein | Absolute Gültigkeitsdauer des Refresh-Tokens in Sekunden. |
| `refresh_reuse_interval_s` | integer | nein | Wiederverwendungsfenster für Refresh-Tokens, 0–30 Sekunden (Standard 5). |
| `backchannel_logout_uri` | string or null | nein | URI für den Backchannel-Logout (`https`). |
| `frontchannel_logout_uri` | string or null | nein | URI für den Frontchannel-Logout (`https`). |
| `frontchannel_logout_session_required` | boolean | nein | Fügt `iss` und `sid` zur URI für den Frontchannel-Logout hinzu. Wird `true` gesetzt, während die Frontchannel-Logout-Einstellung der Umgebung deaktiviert ist, wird 422 zurückgegeben. Standard `false`. |
| `initiate_login_uri` | string | nein | URI für die OIDC-Login-Initiierung (OpenID Connect Core 1.0 §4): Nach einer vom Identitätsanbieter initiierten SAML-Anmeldung wird der Browser an diese URI mit `iss` weitergeleitet, und die Anwendung startet ihren eigenen Authorization-Code-Flow mit `state` und PKCE. Absolute `https`-URL mit einem DNS-Host in Kleinbuchstaben, ohne Fragment oder Benutzerinformationen, höchstens 2048 Byte; nicht erlaubt für `m2m`- und `management`-Anwendungen. Nur eine Anwendung mit dieser URI kann Ziel einer vom Identitätsanbieter initiierten Anmeldung sein. |
| `id_token_org_claims` | boolean | nein | Bei `true` (Standard) enthält das ID-Token einer Organisationsanmeldung `org_id`, `org_slug` und `org_roles`; bei `false` enthält das ID-Token keine Organisations-Claims. Access-Tokens sind nicht betroffen, und ID-Tokens enthalten niemals Berechtigungen. |
| `policy_uri` | string or null | nein | URI der Datenschutzrichtlinie (`https`), die auf dem Zustimmungsbildschirm angezeigt wird. |
| `tos_uri` | string or null | nein | URI der Nutzungsbedingungen (`https`). |
| `client_uri` | string or null | nein | URI der Startseite der Anwendung (`https`). |
| `jwks` | object or null | nein | Eingebettetes JWK-Set (`{"keys":[…]}`): 1–5 öffentliche Schlüssel, höchstens 16 KiB; Member privater Schlüssel werden abgelehnt. Schließt `jwks_uri` gegenseitig aus. |
| `jwks_uri` | string or null | nein | URI eines entfernten JWK-Sets (`https`); schließt `jwks` gegenseitig aus. |
| `software_id` | string or null | nein | Nur für DCR-Anwendungen. |
| `software_version` | string or null | nein | Nur für DCR-Anwendungen. |
| `m2m_token_lifetime_s` | integer or null | nein | Gültigkeitsdauer des Tokens für `m2m`-Anwendungen, 60–86400 Sekunden. |
| `redirect_uris` | string[] | nein | Erlaubte Redirect-URIs, höchstens 50; muss für `m2m` und `management` leer sein. |
| `post_logout_redirect_uris` | string[] | nein | Erlaubte Redirect-URIs nach dem Abmelden, höchstens 50. |
| `connection_ids` | string[] | nein | Auf der Anwendung aktivierte Verbindungen (`conn_…`), geordnet; die Reihenfolge bestimmt die Reihenfolge der Schaltflächen. Höchstens 100. |
| `allowed_first_factors` | string[] | nein | Auf der Anwendung erlaubte Erstfaktoren: Werte aus `password`, `passkey`, `email_otp`, `magic_link`, `sms_otp`, `social`, `enterprise`, ohne Duplikate; werden in dieser Reihenfolge zurückgegeben. Eine leere Liste (Standard) bedeutet, dass die Anwendung keine Einschränkung hinzufügt. Die Menge wird mit den `allowed_first_factors` der Umgebung geschnitten; bleibt keine Methode übrig, `422 policy_conflict`. |
| `allowed_response_modes` | string[] | nein | Die `response_mode`-Werte, die die Anwendung in Autorisierungs- und Pushed-Authorization-Anfragen verwenden darf: `query`, `form_post` (eines oder beide, ohne Duplikate); werden in dieser Reihenfolge zurückgegeben. Standard `["query"]`: Eine Anwendung, die die Autorisierungsantwort per Form-Post erhält, fügt `form_post` explizit hinzu. Eine Autorisierungsanfrage, deren `response_mode` nicht in der Liste steht, wird abgelehnt; eine Anfrage ohne `response_mode` verwendet `query`. Eine leere Liste ergibt 422. JARM-Modi (`jwt`, `query.jwt`, `fragment.jwt`, `form_post.jwt`) werden noch nicht unterstützt. Anwendungen, die über dynamische Client-Registrierung oder ein Client-ID-Metadatendokument registriert wurden, erhalten `["query"]`. |

## Antwort

`201 Created` mit der Anwendung und einem `ETag`-Header.

```json
{
  "id": "app_6f8d0cjgbmf0gtn2rg6pscp3cg",
  "client_id": "app_6f8d0cjgbmf0gtn2rg6pscp3cg",
  "version": 1,
  "created_at": "2026-10-05T10:00:01Z",
  "updated_at": "2026-10-05T10:00:01Z",
  "key": "portal",
  "name": "Portal",
  "app_type": "web",
  "party": "first_party",
  "status": "active",
  "redirect_uris": ["https://portal.example.com/cb"],
  "...": "all other fields from the field reference"
}
```

## Fehler

| HTTP | `code` | Wann |
|---|---|---|
| 401 | `unauthenticated` | Der Schlüssel fehlt, ist ungültig oder wurde widerrufen. |
| 403 | `insufficient_permissions` | Dem Schlüssel fehlt die erforderliche Berechtigung. |
| 409 | `conflict` | Eine Anwendung mit diesem `key` existiert bereits. |
| 422 | `validation_failed` | Ein Feld ist ungültig; `errors[].pointer` benennt es (zum Beispiel `/redirect_uris/0`). |
| 422 | `policy_conflict` | `allowed_first_factors` hat keine Methode gemeinsam mit den Erstfaktoren der Umgebung. |
| 400 | `unknown_field` | Der Body enthält ein Feld, das nicht Teil des Schemas ist. |
| 403 | `quota_exceeded` | Das Tariflimit für Anwendungen ist erreicht. |

## Beispiel

```bash
curl -X POST https://api.eu.keenauth.com/v1/applications \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key":"portal","name":"Portal","app_type":"web","party":"first_party","redirect_uris":["https://portal.example.com/cb"]}'
```

## Antwortfelder

`id` und `client_id` sind die Anwendungs-ID (`app_…`); `version` wird auch als `ETag` zurückgegeben; `created_at`, `updated_at`, `last_token_issued_at` und `last_token_asn` sind schreibgeschützt. Jedes beschreibbare Feld oben wird zurückgegeben. Client-Secrets sind niemals Teil dieser Ressource.
