
# 연결 업데이트

`PATCH /v1/connections/{connection_id}` · 권한 `connections:write`

JSON 병합 패치(`application/merge-patch+json`, RFC 7396)로 연결을 업데이트합니다. `If-Match`가 필요합니다. `key`, `type`, `strategy`, `org_id`는 변경할 수 없습니다. 변경 사항이 없는 패치는 아무것도 기록하지 않으며 버전을 유지합니다. 설정에 비밀 값을 포함하지 마십시오.

## 요청

| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| `connection_id` | string | 예 | 연결 식별자(`conn_…`). |
| `If-Match` | header | 예 | 마지막으로 읽은 연결의 `ETag`. 없으면 `428`, 일치하지 않으면 `412`를 반환합니다. |
| `key` | string | 아니요 | 변경할 수 없으며 같은 값은 허용됩니다. |
| `type` | string | 아니요 | 변경할 수 없습니다. |
| `strategy` | string | 아니요 | 변경할 수 없습니다. |
| `name` | string | 아니요 | 1~128자. |
| `display_name` | string \| null | 아니요 | `null`이면 값을 지웁니다. |
| `status` | string | 아니요 | `active` 또는 `inactive`. |
| `org_id` | string \| null | 아니요 | 변경할 수 없으며 같은 값은 허용됩니다. |
| `allowed_email_domains` | array of strings \| null | 아니요 | 목록을 대체합니다. `null` 또는 `[]`이면 지웁니다. 생성 시와 같은 규칙을 적용하며, 조직 연결에서는 새로 추가된 도메인만 조직의 확인된 도메인과 대조합니다. |
| `allow_external_domains` | boolean | 아니요 | `enterprise`에서만 사용합니다. |
| `jit_mode` | string | 아니요 | `create`, `create_and_update` 또는 `off`. `enterprise`에서만 사용합니다. |
| `email_trust` | boolean | 아니요 | `enterprise`에서만 사용합니다. 조직 연결에서 켜려면 비어 있지 않은 `allowed_email_domains`가 필요하며, 그 안의 모든 도메인이 조직의 확인된 도메인이어야 합니다. |
| `default_role_ids` | array of strings \| null | 아니요 | 목록을 대체합니다. `null` 또는 `[]`이면 지웁니다. 생성 시와 같은 규칙을 적용하며, 새로 추가된 역할만 확인합니다. 따라서 목록에 이미 있던 역할이 나중에 삭제되었더라도 업데이트를 막지 않습니다(로그인 시 건너뜁니다). |
| `trust_idp_mfa` | boolean | 아니요 | `enterprise`에서만 사용합니다. |
| `settings` | object \| null | 아니요 | 재귀적으로 병합됩니다(RFC 7396). `null` 멤버는 해당 키를 삭제하며, `null`이면 모든 설정을 지웁니다. 비밀 값은 포함하지 마십시오. |

## 응답

업데이트된 연결과 새 `ETag`를 포함하여 `200 OK`를 반환합니다.

```json
{
  "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"
}
```

## 패스키 설정

`type: "passkey"`인 경우 `settings` 객체는 아래 키만 허용합니다. 다른 키, 잘못된 유형 또는 허용 범위를 벗어난 값은 `422 validation_failed`와 `/settings/max_credentials_per_user` 같은 `errors[].pointer`로 거부됩니다. `null` 값은 기본값을 의미합니다. 형식 오류는 계획 오류보다 먼저 보고됩니다.

| 키 | 유형 | 참고 |
|---|---|---|
| `rp_id` | string | 없음, `null` 또는 빈 값이면 각 로그인 호스트가 자체 rpId가 됩니다. 그렇지 않으면 환경의 `active` 상태인 사용자 지정 도메인의 호스트 이름(소문자, IDNA A-label)이어야 하며, 그 밖의 값은 `422 validation_failed`(`/settings/rp_id`)입니다. 환경에 패스키가 이미 있으면 [패스키 rpId 변경](change-rp-id.md)을 사용하여 변경하십시오. |
| `rp_name` | string | 최대 128자. |
| `passkey_first_factor_enabled`, `security_key_second_factor_enabled` | boolean | 기본값은 `true`. |
| `user_verification` | string | `preferred`(기본값) 또는 `required`. |
| `max_credentials_per_user` | integer | 1~20, 기본값 20. 소수는 거부됩니다. |
| `require_device_bound_passkeys` | boolean | 요금제 제한: `true`는 Startup이 필요합니다. |
| `attestation_required` | boolean | 요금제 제한: `true`는 Enterprise가 필요합니다. |
| `aaguid_allowlist`, `aaguid_blocklist` | array of UUID strings | 각각 고유 항목 최대 500개(오류는 `/settings/<key>/<index>`를 가리킵니다). 요금제 제한: 비어 있지 않은 목록은 Enterprise가 필요합니다. |
| `related_origins` | array of strings | `https://host[:port]` 형식의 origin. 요금제 제한: 비어 있지 않은 목록은 Enterprise가 필요합니다. |
| `passkey_enrollment_prompt` | string | `off` 또는 `after_login`(기본값). |

요금제 제한이 있는 키에 기본값이 아닌 값을 기록하면 `403 plan_feature_unavailable`과 `feature`, `required_plan` 멤버가 반환됩니다. 요금제 권한을 사용할 수 있게 되기 전까지는 어떤 환경에서도 이 키를 설정할 수 없습니다. 기본값(`false`, `[]`, `null`)을 기록하거나 키를 제거하는 작업은 항상 허용됩니다. 기능을 사용할 수 있게 되면 `related_origins`의 모든 항목은 환경의 활성 상태인 확인된 사용자 지정 도메인이어야 하며, 그렇지 않으면 요청은 `422 related_origin_not_verified`로 실패합니다. 설정은 `settings`가 패치에 포함된 경우에만, 병합 패치를 적용한 뒤에 검증됩니다.

## 오류

| HTTP | code | 발생 조건 |
|---|---|---|
| 400 | `unknown_field` | 패치에 알 수 없거나 읽기 전용인 필드가 있습니다. |
| 404 | `not_found` | 연결이 존재하지 않거나 다른 환경에 속합니다. |
| 409 | `connection_test_required` | 패치가 `enterprise` 연결을 `active`로 설정하거나, `active` 연결의 `allowed_email_domains`에 도메인을 추가하는데, 지난 24시간 안에 결과 구성에 대한 테스트가 성공하지 않았습니다(연결 활성화 참조). 아무것도 기록되지 않습니다. 도메인 제거는 확인하지 않습니다. |
| 409 | `rp_id_change_requires_migration` | 패치가 패스키 연결의 `settings.rp_id`를 변경하는데, 환경에 작동이 중단될 패스키가 있습니다. [패스키 rpId 변경](change-rp-id.md)을 사용하십시오. 아무것도 기록되지 않습니다. |
| 412 | `precondition_failed` | `If-Match`가 현재 버전과 일치하지 않습니다. |
| 415 | `unsupported_media_type` | 콘텐츠 유형이 `application/merge-patch+json`이 아닙니다. |
| 422 | `validation_failed` | 값이 잘못되었거나 변경할 수 없는 필드가 변경되었습니다(`code: immutable`). |
| 422 | `related_origin_not_verified` | 관련 origin이 환경의 확인된 사용자 지정 도메인이 아닙니다. |
| 403 | `plan_feature_unavailable` | 요금제에 설정한 항목이 포함되어 있지 않습니다(`feature`, `required_plan` 멤버). 예: `attestation_required`. |
| 428 | `precondition_required` | `If-Match` 헤더가 없습니다. |
| 401 | `unauthenticated` | 자격 증명이 없거나 잘못되었거나 취소되었습니다. |
| 403 | `insufficient_permissions` | 자격 증명에 필요한 권한이 없습니다. |
| 429 | `rate_limited` | 요청 한도를 초과했습니다. `Retry-After` 기간 이후에 다시 시도하십시오. |
| 503 | `service_unavailable` | 종속 서비스를 일시적으로 사용할 수 없습니다(예: `rp_id` 변경의 패스키 확인을 실행할 수 없어 아무것도 기록되지 않았습니다). `Retry-After` 기간 이후에 다시 시도하십시오. |

## 예시

```bash
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"}'
```
