
# keenauth_directory

The `keenauth_directory` resource creates a SCIM 2.0 directory for an organization. A directory is the endpoint that the organization's identity provider (Okta, Entra ID and others) provisions users and groups to.

```terraform
resource "keenauth_directory" "acme_okta" {
  organization_id = keenauth_organization.acme.id
  name            = "Okta"
  scim_host       = "acme.eu.keenauth.app"
}

output "scim_base_url" {
  value = keenauth_directory.acme_okta.base_url
}
```

`base_url` is `https://<scim_host>/scim/v2/<id>`. Give it to the identity provider together with a SCIM token.

## Changes in place and replacements

`name` and the directory settings change in place. The provider sends a JSON merge patch with only the changed fields and the ETag of the last read as `If-Match`; if the directory changed outside this configuration after that read, the API answers `412`, nothing is changed, and you run plan again. The API takes no settings when it creates a directory, so the settings you configure are applied right after the create, in the same apply.

Changing `organization_id`, `scim_host` or `type` replaces the directory.

- A replacement deletes the old directory first. Deleting a directory is immediate and hard: its tokens, provisioned users, groups, group memberships and pending deprovision holds go with it, and the identity provider's SCIM requests get `401`. A new directory has a new ID and a new base URL, and the identity provider must be pointed at it with a new token.
- Protect a directory you cannot afford to lose with `lifecycle { prevent_destroy = true }`.
- A new directory is `inactive`. The provider does not activate or deactivate it (`keenauth directories activate` and `deactivate` do); `state` is only read.
- Deleting the organization deletes its directories. A directory deleted outside the provider is removed from state and planned again.

## Settings

```terraform
resource "keenauth_directory" "acme_okta" {
  organization_id = keenauth_organization.acme.id
  name            = "Okta"
  scim_host       = "acme.eu.keenauth.app"

  provisioning_mode   = "user_store"
  attribute_allowlist = ["title", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:user:department"]
  delete_action       = "remove_membership"

  mass_deprovision_guard = {
    percent      = 20
    absolute_min = 50
  }
}
```

| Setting | Values | Default |
|---|---|---|
| `provisioning_mode` | `user_store` (environment users, organization memberships and group roles are written) or `mirror` (only directory records are kept) | `user_store` |
| `attribute_allowlist` | Up to 40 optional SCIM attributes kept on directory users: `title`, `usertype`, `phonenumbers` and the enterprise extension keys | empty |
| `unverified_domain_action` | `invite` or `mirror_only`, for a user whose email domain is not verified for the organization | `invite` |
| `delete_action` | `remove_membership` or `delete_user`, for a SCIM `DELETE /Users` | `remove_membership` |
| `on_delete_memberships` | `keep`, `suspend` or `remove`, for memberships from the directory when it is deleted | `keep` |
| `mass_deprovision_guard` | `enabled`, `percent` (5 to 50) and `absolute_min` (10 to 1000); more deprovisionings than both within 5 minutes are held for approval | on, 10, 25 |
| `send_welcome_email` | `true` or `false`: an account activation email for new directory users | `false` |

- A setting you do not configure keeps the server value, and removing a setting from the configuration keeps its last value. In `mass_deprovision_guard`, a field you do not set keeps its value.
- Removing a key from `attribute_allowlist` deletes that attribute from every user record of the directory in the same update. An empty set (`[]`) clears the list.
- `provisioning_mode` cannot change while the directory holds user records; the API answers `409`.

## SCIM tokens

The SCIM token is a secret. The API returns it once, in the response that creates the directory, and no endpoint can read it afterwards. The provider never writes it to state, a plan file, an output or a log. To keep that guarantee, and so that no valid credential exists that nobody holds, the provider revokes the token that the create returns right away.

Create the token for your identity provider with [`keenauth_directory_token`](/docs/terraform/directory-token). It keeps the token in state only encrypted to your RSA public key, and you decrypt it with your private key.

If the provider cannot revoke the initial token, the apply still succeeds and prints a warning with the command that revokes it (`keenauth directories tokens delete <directory_id> <token_id>`).

## Arguments

- `scim_host` is the primary host of the environment: its active custom domain, otherwise `<slug>.<region>.keenauth.app`. It must be a lower-case DNS name that routes to this environment, or the API answers `422`. The API does not check that it is the primary host, so a secondary custom domain is accepted.
- `name` is 1 to 64 characters, without control characters and without leading or trailing whitespace. It does not need to be unique.
- `type` is `scim` and cannot be anything else in GA-1.
- `state`, `base_url`, `created_at`, `etag` and `id` are read-only. The API does not return `scim_host`, so the provider derives it from the host of `base_url`.

## Import

Import by directory ID:

```shell
tofu import keenauth_directory.acme_okta dir_01j9zq3v8c5m2x7k4t6r1n0b3d
```
