
# 環境設定を更新する

`PATCH /v1/environment-settings` · 権限 `environment-settings:write`

JSON マージパッチ（`application/merge-patch+json`、RFC 7396）を使って環境設定を更新します。`If-Match` は必須です。指定がない場合は `428`、古いバージョンの場合は `412` が返されます。設定が一度も書き込まれていない場合、バージョンは `"0"` であり、最初の書き込みで行が作成されます。何も変更しないパッチでは書き込みは行われず、バージョンも変わりません。

## リクエスト

| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| `If-Match` | ヘッダー | はい | 最後に取得した設定の `ETag`（一度も書き込まれていない場合は `"0"`）。指定がない場合は `428`、古い場合は `412`。 |
| `locales.enabled` | string[] | いいえ | 有効にする言語コード（登録済みの言語）。1〜64 件、重複不可。`null` は指定できません。 |
| `locales.default` | string | いいえ | 既定の言語。`locales.enabled` のいずれかである必要があります。`null` は指定できません。 |
| `default_zoneinfo` | string | いいえ | IANA タイムゾーン名（既定値は `UTC`）。`null` は指定できません。 |
| `session.idle_timeout_s` | integer | いいえ | アイドルタイムアウト（秒）。60〜8640000（既定値 259200）。`session.absolute_timeout_s` を超えてはいけません。`null` は指定できません。 |
| `session.absolute_timeout_s` | integer | いいえ | 絶対有効期間（秒）。60〜31536000（既定値 2592000）。`null` は指定できません。 |
| `session.max_concurrent` | integer | いいえ | ユーザーごとの同時セッション数。0〜500。`0` はシステムの上限を意味します（既定値）。`null` は指定できません。 |
| `session.concurrent_mode` | string | いいえ | `evict_oldest`（既定値）または `deny_new`。`null` は指定できません。 |
| `session.anomaly_action` | string | いいえ | `enforce`（既定値）または `log`。`null` は指定できません。 |
| `signup.mode` | string | いいえ | `open`（既定値）、`invite_only` または `closed`。`null` は指定できません。 |
| `signup.email_domain_mode` | string | いいえ | `off`（既定値）、`allowlist` または `denylist`。`null` は指定できません。 |
| `signup.email_domains` | string[] \| null | いいえ | 最大 1000 件のドメイン。リスト全体を置き換えます（RFC 7396 では配列はマージされません）。`null` または `[]` で消去されます。エントリは正規化され（小文字化、IDNA A ラベル）、重複は削除され、リストはソートされて保存されます。モードが `off` の間も保持されます。 |
| `security_notifications.enabled` | boolean | いいえ | マスタースイッチ（既定値 `true`）。`null` は指定できません。 |
| `security_notifications.events` | string[] \| null | いいえ | 12 種類のセキュリティイベントのうちの部分集合（`password_changed`、`password_reset`、`email_changed`、`phone_changed`、`authenticator_added`、`authenticator_removed`、`recovery_code_used`、`recovery_codes_regenerated`、`account_locked`、`breached_password_detected`、`new_device_sign_in`、`account_recovery_started`）。リスト全体を置き換え、正規の順序で返されます。`null` または `[]` で消去されます（イベントなし）。 |
| `account_recovery.mode` | string | いいえ | `self_service_waiting`（既定値）、`admin_only` または `disabled`。`null` は指定できません。 |
| `account_recovery.waiting_hours` | integer | いいえ | 24〜168 時間（既定値 72）。すべてのモードで保存されます。`null` は指定できません。 |
| `account_recovery.support_url` | string | いいえ | 空、または最大 2048 バイトの `https://` URL。ユーザー情報やフラグメントを含まないこと。リカバリーが `disabled` の場合に表示されます。`null` は指定できません。 |
| `mfa.email_second_factor_enabled` | boolean | いいえ | メールによる第二要素のオン／オフ（既定値 `false`）。`null` は指定できません。 |
| `mfa.email_second_factor_acr` | string | いいえ | メールの要素が満たす保証レベル：`1fa`（既定値）または `mfa`。`null` は指定できません。 |
| `mfa.totp_issuer_label` | string | いいえ | TOTP の発行者ラベル。最大 64 文字。空の場合は環境の表示名になります。制御文字、`:`、先頭・末尾の空白は使用できません。`null` は指定できません。 |
| `mfa.recovery_codes_enabled` | boolean | いいえ | リカバリーコードのオン／オフ（既定値 `true`）。`null` は指定できません。 |
| `mfa.recovery_code_count` | integer | いいえ | リカバリーコードの数。8〜16（既定値 10）。`null` は指定できません。 |
| `mfa.required` | boolean | いいえ | 環境内のすべてのサインインで第二要素を必須にします（既定値 `false`）。アプリケーション、組織、リクエストの要件と OR で結合されます。これを下回る既存の SSO セッションには、ステップアップが求められます（`prompt=none` を伴う `interaction_required`）。`null` は指定できません。 |
| `mfa.min_acr` | string | いいえ | 環境内のすべてのサインインが満たす必要がある最低の保証レベル：`1fa`（既定値、効果なし）、`mfa` または `phr`。環境、アプリケーション、組織、リクエストのしきい値のうち最も高いものが適用され、新しいサインインと SSO セッションの再利用の両方に適用されます。`null` は指定できません。 |
| `mfa.enrollment_grace_days` | integer | いいえ | 第二要素が未登録のユーザーが登録せずにサインインし続けられる日数。登録が初めて必要とされた時点から数えます。0〜14（既定値 `0`、猶予なし）。猶予が延期するのは、環境と組織の観点で必要とされるものだけです。アプリケーションの `min_acr` とリクエストの `acr_values` は延期されません。範囲外の場合は、`out_of_range` を伴う `422 validation_failed` が返されます。短縮した場合は直ちに有効になります。`null` は指定できません。 |
| `frontchannel_logout_enabled` | boolean | いいえ | フロントチャネルログアウトのオン／オフ（既定値 `false`）。オフにしても登録済みの URI は保持されます。`null` は指定できません。 |
| `allowed_first_factors` | string[] | いいえ | 許可する第一要素。`password`、`passkey`、`email_otp`、`magic_link`、`sms_otp`、`social`、`enterprise` のうち 1 つ以上を指定し、重複は不可です。リスト全体を置き換え、この順序で返されます。既定値は `password`、`passkey`、`social`、`enterprise` です。`email_otp`、`magic_link`、`sms_otp` は明示的に追加した場合にのみ有効になります。空のリストを指定すると `422 required` が返されます（誰もサインインできない環境になるためです）。`null` は指定できません。 |

## 動作

- グループは再帰的にマージされます。`locales`、`session`、`signup`、`security_notifications`、`account_recovery`、`mfa` の内側では、変更するフィールドだけを送信してください。グループ自体を `null` にすることはできません。
- セッションの有効期間の短縮、同時セッション数の上限の引き下げ、サインアップやアカウントリカバリーの範囲の縮小、メールによる第二要素を `mfa` から `1fa` に下げること、`allowed_first_factors` から要素を削除することは、新しいセッションとサインインに直ちに適用されます。既存のセッションは、それぞれ元の有効期間を維持します。
- 検証エラーには、フィールドの JSON ポインターが含まれます。例えば、`out_of_range` を伴う `/session/idle_timeout_s` です。リストのエントリのエラーは、そのエントリを指します。例えば、`unknown_value`（不明な値）を伴う `/allowed_first_factors/1` や、`duplicate`（重複した値）を伴う同じポインターです。
- `allowed_first_factors` は、アプリケーションと組織のポリシーとの積集合になります。これらは、この集合を狭めることしかできません。
- 新しい集合が、独自の `allowed_first_factors` を持つアプリケーションとの間で共通の方式を一つも残さない場合、リクエストは `422 policy_conflict` を返します。先にアプリケーションの集合を変更してください。
- 監査レコードと変更イベントには、変更されたフィールドの名前のみが含まれ、値は含まれません。アタック保護は別のリソースであり、このリソースには含まれません。

## レスポンス

`200 OK`、更新後の設定、および新しい `ETag` を返します。

```json
{
  "locales": {"enabled": ["en", "tr"], "default": "tr"},
  "default_zoneinfo": "Europe/Istanbul",
  "session": {"idle_timeout_s": 3600, "absolute_timeout_s": 2592000, "max_concurrent": 5, "concurrent_mode": "evict_oldest", "anomaly_action": "enforce"},
  "signup": {"mode": "invite_only", "email_domain_mode": "allowlist", "email_domains": ["example.com"]},
  "security_notifications": {"enabled": true, "events": ["password_changed", "password_reset"]},
  "account_recovery": {"mode": "self_service_waiting", "waiting_hours": 72, "support_url": ""},
  "mfa": {"email_second_factor_enabled": false, "email_second_factor_acr": "1fa", "totp_issuer_label": "Acme", "recovery_codes_enabled": true, "recovery_code_count": 10, "required": false, "min_acr": "1fa", "enrollment_grace_days": 0},
  "frontchannel_logout_enabled": false,
  "allowed_first_factors": ["password", "passkey", "magic_link", "enterprise"],
  "updated_at": "2026-10-05T09:30:00.123456Z"
}
```

## エラー

| HTTP | code | 発生条件 |
|---|---|---|
| 400 | `unknown_field` | パッチに不明なフィールドまたは読み取り専用のフィールドが含まれている、あるいは JSON オブジェクトではありません（`malformed_request`）。 |
| 412 | `precondition_failed` | `If-Match` が現在のバージョンと一致しません。 |
| 415 | `unsupported_media_type` | コンテンツタイプが `application/merge-patch+json` ではありません。 |
| 422 | `validation_failed` | 値が無効です（ポインターがフィールドを示します）。または、`null` を指定できないフィールドに `null` が設定されました（`code: invalid`）。 |
| 422 | `policy_conflict` | 新しい `allowed_first_factors` が、独自の集合を持つアプリケーションとの間で共通の方式を一つも残しません。 |
| 428 | `precondition_required` | `If-Match` ヘッダーがありません。 |
| 401 | `unauthenticated` | 認証情報がない、無効である、または取り消されています。 |
| 403 | `insufficient_permissions` | 認証情報に必要な権限がありません。 |
| 429 | `rate_limited` | レート制限を超えました。`Retry-After` の期間を待ってから再試行してください。 |
| 503 | `service_unavailable` | 依存先が一時的に利用できません。`Retry-After` の期間を待ってから再試行してください。 |

## 例

メールのマジックリンクを有効にし、パスワードを無効にする：

```bash
curl -X PATCH https://api.eu.keenauth.com/v1/environment-settings \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/merge-patch+json" \
  -H 'If-Match: "0"' \
  -d '{"allowed_first_factors":["passkey","magic_link","social","enterprise"]}'
```

セッションとサインアップの設定：

```bash
curl -X PATCH https://api.eu.keenauth.com/v1/environment-settings \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/merge-patch+json" \
  -H 'If-Match: "0"' \
  -d '{"session":{"idle_timeout_s":3600},"signup":{"mode":"invite_only","email_domain_mode":"allowlist","email_domains":["example.com"]}}'
```
