Apply a configuration plan
POST /v1/config-plans/{plan_id}:apply · permission config:write, the read permissions of the plan and the write permission of each kind it changes
Applies a stored plan to the environment. Every change is written in one transaction: if one fails, none is kept. A plan can be applied once.
Request
| Parameter | Description |
|---|---|
plan_id |
The plan id, cfgp_…. |
The body is optional.
| Field | Description |
|---|---|
resolved_secrets |
Object of secret_ref name → value for every change with requires_secret: true (for example KEENAUTH_CONNECTION_GITHUB_CLIENT_SECRET). Values are at most 8 KiB. They are never stored by the plan, logged or returned. |
confirm_deletions |
List of <kind>/<key> deletions you confirm, for example connection/legacy. The plan's deletion_requires_confirmation warnings list the deletions that need it. |
sp_host |
The environment's service-provider host, for example login.example.com. Required only when the plan creates the OIDC material of an enterprise connection (the callback https://<sp_host>/sso/<connection id>/callback is fixed from it); a request that does not need it must not send it. |
- The write permissions are
environment-settings:write,identity-settings:write,attack-protection:write,branding:write(forbrandingandapplication_branding),connections:write,apis:write,roles:writeandapplications:write, only for kinds with a change other thanno_op. - Before writing, the target is read again. If any planned resource's version or the content of the plan's kinds changed after the plan was made, nothing is written, the plan becomes
conflictedand the request fails with409 config_conflict. Make a new plan. Withprune, the kinds that refer to the planned resources are compared too, and the references between resources are checked again; a broken reference also makes the planconflicted. - Deleting a connection, or an application that received a token in the last 30 days, must be repeated in
confirm_deletions. Otherwise the request fails with409 deletion_not_confirmedand the plan staysplanned. - The OIDC material of an enterprise connection (
spec.oidc) and its client secret are written to the federation service after the connection record. If that second write is refused, the plan staysplanned, the connection record may already exist, and a new plan writes only the missing material. Aspec.oidcofnullleaves the material unchanged. The client secret of a social connection cannot be written yet: a plan with such arequires_secretchange returns501 not_implementedafter the secrets are checked. Nothing is written. Idempotency-Keyis supported. Send it without secrets in the body when you can: the key's record keeps a hash of the body.
Response
200 OK with Cache-Control: no-store: the plan in the form of Get a configuration plan with status: applied and applied_at.
The configuration of the affected resources before the change is kept as a revision (the newest 50 per environment, at most 90 days). The apply writes one config.applied entry to the environment's management log with the counts of created, updated, deleted and unchanged resources; each changed resource also writes its own entry.
Errors
| HTTP | code | When |
|---|---|---|
| 400 | malformed_request, unknown_field |
The body is not JSON or has a field other than resolved_secrets, confirm_deletions and sp_host. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks a required permission; required_permissions lists all of them. |
| 404 | not_found |
The plan does not exist, belongs to another environment or was deleted. |
| 409 | config_conflict |
The target changed after the plan was made; the plan is now conflicted. |
| 409 | config_plan_not_applicable |
The plan was already applied or is conflicted, or another request is applying it now (plan_status: applying); plan_status gives its status. |
| 409 | deletion_not_confirmed |
A protected deletion is missing from confirm_deletions; unconfirmed_deletions lists them. |
| 409 | conflict |
Another resource already uses a unique value of a change (errors[].pointer is /changes/<i>/spec/<field>, code duplicate); the plan stays planned. |
| 409 | connection_in_use |
The connection to delete is still in use; the plan stays planned. |
| 409 | connection_test_required |
A change creates an enterprise connection active or activates one without a successful test sign-in (errors[].pointer is /changes/<i>/spec, code test_required); the plan stays planned. |
| 410 | config_plan_expired |
The plan's hour has passed; make a new plan. |
| 413 | config_document_too_large |
The changes, or the revision kept for them (at most 10 MiB), are too large to apply in one request; plan fewer kinds. |
| 422 | validation_failed |
See below. |
| 422 | policy_conflict |
The change conflicts with an environment policy; the plan stays planned. |
| 429 | rate_limited |
The config_plan rate limit (shared with plan creation) was exceeded, or too many plans are being computed or applied for this environment at once; the plan stays planned; retry after the Retry-After period. |
| 501 | not_implemented |
The plan needs the client secret of a social connection, which cannot be written yet. |
| 503 | service_unavailable |
A dependency (the directory or, for enterprise OIDC material, the federation service) is temporarily unavailable or plan capacity is temporarily full; nothing was written or, for the federation service, only the connection record was. Retry after the Retry-After period. |
errors[].pointer |
errors[].code |
Meaning |
|---|---|---|
/resolved_secrets/<NAME> |
secret_missing |
The plan needs this secret. |
/resolved_secrets/<NAME> |
secret_unused |
The plan does not need this secret. |
/resolved_secrets/<NAME> |
secret_invalid |
The value is empty, longer than 8 KiB or not text. |
/resolved_secrets/<NAME> |
invalid |
The name does not have the KEENAUTH_… form (A-Z, 0-9, _). |
/sp_host |
sp_host_required, sp_host_unused, invalid |
The plan creates OIDC material and no host was given, no host is needed, or the host is not a lowercase DNS name. |
/changes/<i>/spec/oidc/... |
as in the connection OIDC API | The federation service rejected the material at this position of the plan's changes. |
/confirm_deletions/<i> |
duplicate, not_a_deletion |
The item is repeated or is not a deletion in the plan. |
/confirm_deletions/<i> |
invalid |
The item does not have the <kind>/<key> form. |
/resolved_secrets, /confirm_deletions |
too_many |
More than 5,000 entries. |
/changes/<i>/spec/... |
as in the resource's own API | The environment rejected the change at this position of the plan's changes. |
Example
curl -X POST "https://api.eu.keenauth.com/v1/config-plans/cfgp_01m4qpqtywfs7930tb6kqn5rc5:apply" \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"confirm_deletions": ["connection/legacy"]}'
keenauth config apply cfgp_01m4qpqtywfs7930tb6kqn5rc5 --confirm-deletion connection/legacy
keenauth config apply --secrets-from-env reads each secret the plan needs from the environment variable of the same name and never prints it.