
# Export the configuration

`GET /v1/config-export` · permission `config:read` and the read permission of each exported kind

Returns the environment's configuration as one environment-independent document, so you can review it, keep it in version control or apply it to another environment later. The document has no environment-specific ids, versions, timestamps or secrets: resources refer to each other by `key`. The same configuration always produces a byte-identical document (kinds in the order below, then by `key`; set-like lists sorted). The response is JSON, which is also valid YAML; `keenauth config export` prints YAML by default.

## Request

The environment comes from the credential. The only query parameter is optional.

| Parameter | Description |
|---|---|
| `kinds` | Comma-separated kinds to export, for example `kinds=connection,api`. Without it every kind is exported. |

| Kind | `key` | Permissions besides `config:read` |
|---|---|---|
| `environment_settings` | `default` | `environment-settings:read` |
| `identity_settings` | `default` | `identity-settings:read` |
| `attack_protection` | `default` | `attack-protection:read` |
| `branding` | `default` | `branding:read` |
| `connection` | connection `key` | `connections:read` |
| `api` | API `key` | `apis:read`, `applications:read` |
| `role` | role `key` | `roles:read`, `apis:read` |
| `application` | application `key` | `applications:read`, `apis:read`, `connections:read` |
| `application_branding` | application `key` | `branding:read`, `applications:read` |

`api`, `role` and `application` also need the permissions of the kinds they refer to, because references are resolved to `key`s. `config:read` alone grants no resource read.

## Response

`200 OK` with `Cache-Control: no-store`.

- References use `key`s: `application.default_api`, `application.connections` (button order is kept), `application.api_grants[].api` and `api.introspection_applications`.
- An enterprise OIDC connection carries its federation material as `oidc` (`issuer`, `client_id`, `client_auth_method`, `provider_profile`); the redirect URI, SP host and the secret itself are environment specific and are not exported, and `oidc` is `null` when no material was written yet. In a document you apply, `oidc: null` leaves the material unchanged. The Entra tenant id is not readable, so a connection with the `entra` profile cannot be managed through the document yet.
- Secret values are never exported. A secret you supplied to KeenAuth (the `client_secret` of a social or enterprise OIDC connection) appears as a placeholder, `{"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_<KEY>_CLIENT_SECRET"}}`; the CLI reads the value from that environment variable when the document is applied. Other connections have `"client_secret": null`. Secrets KeenAuth issues (application client secrets, API keys, webhook signing secrets) and private keys are not exported at all; the target environment issues its own. `jwks` contains public keys only.
- The built-in system API is not exported; it exists in every environment. Organization-owned applications and applications registered by the client itself (Dynamic Client Registration, Client ID Metadata Document) are not exported either; each one is listed in `warnings` with code `resource_skipped`.
- A reference that cannot be resolved (for example to a skipped application) is removed from the document and listed in `warnings` with code `reference_dropped` and a JSON `pointer`.
- `attack_protection` is the object you wrote with [Replace attack protection](../attack-protection/put.md), not the effective values. Every section and field is written; `null` means not set, so the target environment applies its own defaults, security floors and plan. A promotion therefore never pins the source's defaults. When the target's plan does not include a written setting (for example `risk_policy.mode: enforce`), applying the plan fails with `403 plan_feature_unavailable` and nothing is written.
- `role` is an environment role: `name`, `description`, `is_privileged`, `assignable_in_self_service` and `permissions`, each permission written as `{"api": "<API key>", "value": "<permission value>"}` (ids are environment specific, so they never appear). The built-in roles `admin` and `member` are read-only: they are not exported and listed in `warnings` with code `resource_skipped` and reason `system_role`; a document cannot create, change or delete them (`422`, `key_in_use`). Organization roles are data, not configuration, and are not exported. A role may refer to the built-in system API's permissions. Deleting a role that is still assigned fails; unassign it first.
- `branding` is the environment's draft theme, custom CSS and page template; `application_branding` is an application's draft theme and only appears for applications that have one. Text overrides and organization themes are not exported yet.
- If two placeholders end up with the same variable name (keys that differ only in `-` and `_`), both resources are listed in `warnings` with code `secret_ref_name_shared`; rename one of the variables in your file.
- The document's JSON Schema is published at `https://docs.keenauth.com/config/schema/v1.json`; point your editor at it for completion and validation.

```json
{
  "apiVersion": "config.keenauth.com/v1",
  "kinds": ["connection", "api", "application"],
  "resources": [
    {"kind": "connection", "key": "db", "spec": {"type": "database", "strategy": "password", "name": "db", "display_name": null, "status": "active", "settings": {}, "client_secret": null}},
    {"kind": "api", "key": "orders", "spec": {"identifier": "https://api.example.com/orders", "name": "Orders", "access_token_lifetime_s": 3600, "token_format": "jwt", "rbac_mode": "off", "allow_offline_access": false, "require_resource_indicator": false, "dpop_required": false, "mcp_profile": false, "first_party_access": "all", "introspection_applications": [], "permissions": [{"value": "orders:read", "display_name": null, "description": null, "consent_text_i18n": {}, "sensitivity": "normal"}]}},
    {"kind": "application", "key": "web", "spec": {"name": "Web", "app_type": "spa", "default_api": "orders", "connections": ["db"], "api_grants": [{"api": "orders", "scopes": ["orders:read"], "default_scopes": []}], "redirect_uris": ["https://app.example.com/callback"]}}
  ],
  "warnings": [
    {"code": "resource_skipped", "kind": "application", "key": "partner-bot", "reason": "organization_owned"}
  ]
}
```

The `application` spec above is shortened; the full field list is in the API reference.

## Errors

| HTTP | code | When |
|---|---|---|
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks a required permission; `required_permissions` lists all of them. |
| 413 | `config_document_too_large` | The document would exceed 5,000 resources or 10 MiB; export fewer kinds with `kinds`. |
| 422 | `validation_failed` | `kinds` is repeated, longer than 256 characters or names an unknown kind. |
| 429 | `rate_limited` | The rate limit was exceeded; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry after the `Retry-After` period. |

## Example

```bash
curl "https://api.eu.keenauth.com/v1/config-export?kinds=connection,api,application" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"

keenauth config export --kinds connection,api,application > keenauth.yaml
```
