Update a connection
PATCH /v1/connections/{connection_id} · permission connections:write
Updates a connection with a JSON merge patch (application/merge-patch+json, RFC 7396). If-Match is required. key, type, strategy and org_id cannot be changed. A patch that changes nothing writes nothing and keeps the version. Settings must not contain secrets.
Request
| Field | Type | Required | Description |
|---|---|---|---|
connection_id |
string | yes | Connection identifier (conn_…). |
If-Match |
header | yes | The ETag of the connection as last read. Missing: 428; stale: 412. |
key |
string | no | Cannot change; the same value is accepted. |
type |
string | no | Cannot change. |
strategy |
string | no | Cannot change. |
name |
string | no | 1-128 characters. |
display_name |
string | null | no | null clears it. |
status |
string | no | active or inactive. |
org_id |
string | null | no | Cannot change; the same value is accepted. |
allowed_email_domains |
array of strings | null | no | Replaces the list; null or [] clears it. Same rules as on create; on an organization connection only newly added domains are checked against the organization's verified domains. |
allow_external_domains |
boolean | no | enterprise only. |
jit_mode |
string | no | create, create_and_update or off. enterprise only. |
email_trust |
boolean | no | enterprise only. Turning it on for an organization connection needs a non-empty allowed_email_domains in which every domain is a verified domain of the organization. |
default_role_ids |
array of strings | null | no | Replaces the list; null or [] clears it. Same rules as on create; only newly added roles are checked, so a role already in the list that was deleted later does not block the update (it is skipped at sign-in). |
trust_idp_mfa |
boolean | no | enterprise only. |
settings |
object | null | no | Merged recursively (RFC 7396); a null member deletes that key; null clears all settings. No secrets. |
Response
200 OK with the updated connection and the new ETag.
{
"id": "conn_0k3v8m1q2x9dz4h7s5t6w0y1ab",
"key": "google",
"type": "social",
"strategy": "google",
"name": "Google",
"display_name": "Sign in with Google",
"status": "active",
"org_id": null,
"allowed_email_domains": [],
"allow_external_domains": false,
"jit_mode": null,
"email_trust": null,
"default_role_ids": [],
"trust_idp_mfa": null,
"allow_idp_initiated": null,
"idp_initiated_default_application_id": null,
"idp_initiated_allowed_application_ids": [],
"settings": {},
"created_at": "2026-10-05T09:30:00.123456Z",
"updated_at": "2026-10-05T09:30:00.123456Z"
}
Passkey settings
For type: "passkey" the settings object accepts only the keys below. Any other key, a wrong type or an out-of-range value is rejected with 422 validation_failed and an errors[].pointer such as /settings/max_credentials_per_user. A null value means the default. Shape errors are reported before plan errors.
| Key | Type | Notes |
|---|---|---|
rp_id |
string | Absent, null or empty: each sign-in host is its own rpId. Otherwise the host name of an active custom domain of the environment (lower-case, IDNA A-label); any other value is 422 validation_failed (/settings/rp_id). Once the environment has passkeys, change it with Change the passkey rpId. |
rp_name |
string | Up to 128 characters. |
passkey_first_factor_enabled, security_key_second_factor_enabled |
boolean | Default true. |
user_verification |
string | preferred (default) or required. |
max_credentials_per_user |
integer | 1-20, default 20; fractions are rejected. |
require_device_bound_passkeys |
boolean | Plan-gated: true needs Startup. |
attestation_required |
boolean | Plan-gated: true needs Enterprise. |
aaguid_allowlist, aaguid_blocklist |
array of UUID strings | At most 500 unique entries each (errors point at /settings/<key>/<index>). Plan-gated: a non-empty list needs Enterprise. |
related_origins |
array of strings | https://host[:port] origins. Plan-gated: a non-empty list needs Enterprise. |
passkey_enrollment_prompt |
string | off or after_login (default). |
Writing a non-default value of a plan-gated key fails with 403 plan_feature_unavailable and the members feature and required_plan. Until plan entitlements are available, these keys cannot be set in any environment; writing a default value (false, [], null) or removing the key is always allowed. When the feature is available, every related_origins entry must be an active verified custom domain of the environment, otherwise the request fails with 422 related_origin_not_verified. The settings are validated after the merge patch is applied, only when settings is part of the patch.
Errors
| HTTP | code | When |
|---|---|---|
| 400 | unknown_field |
The patch contains an unknown or read-only field. |
| 404 | not_found |
The connection does not exist or belongs to another environment. |
| 409 | connection_test_required |
The patch sets an enterprise connection to active, or adds a domain to allowed_email_domains of an active one, without a successful test of the resulting configuration in the last 24 hours (see Activate a connection); nothing is written. Removing domains is not checked. |
| 409 | rp_id_change_requires_migration |
The patch changes settings.rp_id of a passkey connection while the environment has passkeys that would stop working; use Change the passkey rpId. Nothing is written. |
| 412 | precondition_failed |
If-Match does not match the current version. |
| 415 | unsupported_media_type |
The content type is not application/merge-patch+json. |
| 422 | validation_failed |
A value is invalid or an immutable field changed (code: immutable). |
| 422 | related_origin_not_verified |
A related origin is not a verified custom domain of the environment. |
| 403 | plan_feature_unavailable |
The plan does not include a setting you set (feature, required_plan members), for example attestation_required. |
| 428 | precondition_required |
The If-Match header is missing. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. |
| 429 | rate_limited |
The rate limit was exceeded; retry after the Retry-After period. |
| 503 | service_unavailable |
A dependency is temporarily unavailable (for example, the passkey check of an rp_id change could not run, so nothing is written); retry after the Retry-After period. |
Example
curl -X PATCH https://api.eu.keenauth.com/v1/connections/conn_0k3v8m1q2x9dz4h7s5t6w0y1ab \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/merge-patch+json" \
-H 'If-Match: "1"' \
-d '{"display_name":"Sign in with Google"}'