Create an application
POST /v1/applications · permission applications:write
Creates an application (an OAuth/OIDC client) in the environment of the calling key. key, name, app_type and party are required; every other field gets a safe default derived from the application type. The response carries an ETag that you send as If-Match when updating or deleting. This operation does not create a client secret; secrets and keys are managed through the application credential endpoints.
Request
Body (application/json). Unknown fields are rejected. Only key, name, app_type and party are required.
| Field | Type | Required | Description |
|---|---|---|---|
key |
string | yes | Stable configuration key, ^[a-z0-9_-]{1,64}$, unique per environment. Required on create; cannot change afterwards. |
name |
string | yes | Display name, 1-100 characters. |
app_type |
string | yes | web, spa, native, m2m, device or management. Required on create; cannot change afterwards. |
party |
string | yes | first_party or third_party. Required on create; can only change from first_party to third_party. |
owner_org_id |
string or null | no | org_… id of the owning organization; only for m2m applications; cannot change. |
status |
string | no | active or suspended. A suspended application cannot get new tokens. |
allowed_web_origins |
string[] | no | Allowed CORS origins (https://host[:port]), at most 20, no wildcards. |
organization_usage |
string | no | deny, allow or require. Governs the organization authorization parameter (an org_… id or the organization's slug): deny refuses it, allow makes it optional, require makes it mandatory. The token carries org_id only after the user's membership is verified. |
org_access_mode |
string | no | Organization sign-in access: all_organizations (default; every member of every organization), enabled_organizations (only organizations where the application is enabled) or assigned_only (additionally only assigned memberships or directory groups). See organization applications. |
registration_mode |
string or null | no | open, invite_only or closed; empty inherits the environment setting. |
registration_source |
string | no | dashboard or management_api on create (default management_api); cannot change. Responses may also show dcr or cimd. |
verification_status |
string | no | verified or unverified. |
security_profile |
string | no | baseline (the only writable profile today). |
token_endpoint_auth_method |
string | no | private_key_jwt, client_secret_basic, client_secret_post or none; must be allowed for the app_type. |
grant_types |
string[] | no | Allowed grant types; a subset of what the app_type permits. |
default_api_id |
string or null | no | api_… id of the API used when a request has no resource. |
require_par |
boolean | no | Require pushed authorization requests. |
require_state |
boolean | no | Require state. |
require_nonce |
boolean | no | Require nonce. |
pkce_required |
boolean | no | Require PKCE; can be disabled only for a confidential web application. Without PKCE, nonce is the only defense against authorization code injection, so require_nonce must stay on outside development environments (otherwise validation_failed on /require_nonce). |
skip_consent |
boolean | no | Skip the consent screen; first-party applications only. |
token_binding_policy |
string | no | none or dpop_required. |
login_host |
string or null | no | One of the environment's login hosts (lower-case DNS name). |
default_max_age_s |
integer or null | no | Default max_age in seconds. |
min_acr |
string or null | no | Minimum authentication assurance: urn:idp:acr:1fa, urn:idp:acr:mfa or urn:idp:acr:phr. |
access_token_lifetime_s |
integer or null | no | Access token lifetime, 60-86400 seconds. |
refresh_idle_s |
integer or null | no | Refresh token idle lifetime in seconds; not above refresh_absolute_s. |
refresh_absolute_s |
integer or null | no | Refresh token absolute lifetime in seconds. |
refresh_reuse_interval_s |
integer | no | Refresh token reuse window, 0-30 seconds (default 5). |
backchannel_logout_uri |
string or null | no | Back-channel logout URI (https). |
frontchannel_logout_uri |
string or null | no | Front-channel logout URI (https). |
frontchannel_logout_session_required |
boolean | no | Adds iss and sid to the front-channel logout URI. Setting it to true while the environment's front-channel logout setting is off returns 422. Default false. |
initiate_login_uri |
string | no | OIDC login initiation URI (OpenID Connect Core 1.0 §4): after an IdP-initiated SAML sign-in the browser is sent here with iss, and the application starts its own authorization code flow with state and PKCE. Absolute https URL with a lower-case DNS host, no fragment or user information, at most 2048 bytes; not allowed for m2m and management applications. Only an application with this URI can be an IdP-initiated target. |
id_token_org_claims |
boolean | no | When true (default), the ID token of an organization sign-in carries org_id, org_slug and org_roles; when false, the ID token carries no organization claims. Access tokens are not affected, and ID tokens never carry permissions. |
policy_uri |
string or null | no | Privacy policy URI (https), shown on the consent screen. |
tos_uri |
string or null | no | Terms of service URI (https). |
client_uri |
string or null | no | Application home page URI (https). |
jwks |
object or null | no | Inline JWK Set ({"keys":[…]}): 1-5 public keys, at most 16 KiB; private key members are rejected. Mutually exclusive with jwks_uri. |
jwks_uri |
string or null | no | Remote JWK Set URI (https); mutually exclusive with jwks. |
software_id |
string or null | no | DCR applications only. |
software_version |
string or null | no | DCR applications only. |
m2m_token_lifetime_s |
integer or null | no | Token lifetime for m2m applications, 60-86400 seconds. |
redirect_uris |
string[] | no | Allowed redirect URIs, at most 50; must be empty for m2m and management. |
post_logout_redirect_uris |
string[] | no | Allowed post-logout redirect URIs, at most 50. |
connection_ids |
string[] | no | Connections enabled on the application (conn_…), ordered; the order is the button order. At most 100. |
allowed_first_factors |
string[] | no | First factors allowed on the application: values from password, passkey, email_otp, magic_link, sms_otp, social, enterprise, no duplicates; returned in this order. An empty list (the default) means the application adds no restriction. The set is intersected with the environment's allowed_first_factors; if no method is left, 422 policy_conflict. |
allowed_response_modes |
string[] | no | The response_mode values the application may use in authorization and pushed authorization requests: query, form_post (one or both, no duplicates); returned in this order. Default ["query"]: an application that receives the authorization response by form post adds form_post explicitly. An authorization request whose response_mode is not in the list is rejected; a request without response_mode uses query. An empty list returns 422. JARM modes (jwt, query.jwt, fragment.jwt, form_post.jwt) are not supported yet. Applications registered through dynamic client registration or a client ID metadata document get ["query"]. |
Response
201 Created with the application and an ETag header.
{
"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"
}
Errors
| HTTP | code |
When |
|---|---|---|
| 401 | unauthenticated |
The key is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The key lacks the required permission. |
| 409 | conflict |
An application with this key already exists. |
| 422 | validation_failed |
A field is invalid; errors[].pointer names it (for example /redirect_uris/0). |
| 422 | policy_conflict |
allowed_first_factors has no method in common with the environment's first-factor set. |
| 400 | unknown_field |
The body has a field that is not part of the schema. |
| 403 | quota_exceeded |
The plan limit for applications is reached. |
Example
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"]}'
Response fields
id and client_id are the application id (app_…); version is also returned as ETag; created_at, updated_at, last_token_issued_at and last_token_asn are read-only. Every writable field above is returned. Client secrets are never part of this resource.