
# Modifier le rpId de la clé d'accès d'une connexion

`POST /v1/connections/{connection_id}:change-rp-id` · autorisation `connections:write`

Déplace une connexion par clé d'accès vers un nouveau rpId et ouvre une fenêtre de migration. Une clé d'accès est liée au rpId avec lequel elle a été enregistrée. Une fois que les utilisateurs disposent de clés d'accès, c'est le seul moyen de modifier le rpId : un `PATCH` qui modifie `settings.rp_id` est rejeté avec `409 rp_id_change_requires_migration`.

Pendant la fenêtre, les utilisateurs peuvent encore se connecter avec les clés d'accès de l'ancien rpId, et les nouvelles clés d'accès sont enregistrées sur le nouveau rpId. À la fin de la fenêtre, ou lorsque vous y mettez fin plus tôt avec [Terminer la migration du rpId](complete-rp-id-migration.md), les clés d'accès encore liées à l'ancien rpId sont révoquées (motif `rp_id_changed`). Les utilisateurs qui n'ont aucune autre méthode de connexion ont alors besoin de la connexion sans mot de passe par adresse e-mail ou de la récupération de compte. Une seule migration peut être en cours dans un environnement à la fois.

Le rpId de la connexion, l'enregistrement de migration, l'entrée d'audit de gestion et l'événement `passkey_rp_id.migration_started` sont écrits ensemble. Un domaine personnalisé qui est le rpId, ou l'ancien rpId d'une migration en cours, ne peut pas être supprimé (`409 domain_in_use_by_rp_id`).

## Requête

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `connection_id` | path | oui | ID de la connexion par clé d'accès (`conn_…`). |
| `If-Match` | header | oui | L'`ETag` de la connexion (voir [Obtenir une connexion](get.md)). |
| `Idempotency-Key` | header | non | Clé facultative qui rend sûre une requête relancée (16 à 64 caractères). |
| `new_rp_id` | string | oui | Le nouveau rpId : le nom d'hôte d'un domaine personnalisé `active` de l'environnement (en minuscules, étiquette A IDNA), ou une chaîne vide pour utiliser chaque hôte de connexion comme son propre rpId. 253 octets maximum. |
| `confirm_rp_id` | string | oui | `new_rp_id` saisi à nouveau. |
| `migration_window_days` | integer | non | Nombre de jours pendant lesquels les clés d'accès de l'ancien rpId continuent de fonctionner : 30 à 365, valeur par défaut 90. |

```json
{
  "new_rp_id": "login.example.com",
  "confirm_rp_id": "login.example.com",
  "migration_window_days": 90
}
```

## Réponse

`200 OK` ; l'enregistrement de migration et un en-tête `ETag` avec la nouvelle version de la connexion.

```json
{
  "id": "rpm_01j9xr4a6b8c0d2e4f6g8h0j2k",
  "connection_id": "conn_01j9xp6q0r1s5t7v9w1x3y5z7b",
  "previous_rp_id": null,
  "new_rp_id": "login.example.com",
  "status": "active",
  "started_at": "2026-10-27T10:00:00Z",
  "ends_at": "2027-01-25T10:00:00Z",
  "completed_at": null,
  "revoked_count": null,
  "new_registration_count": null,
  "fallback_enabled_by_migration": false
}
```

| Champ | Description |
|---|---|
| `previous_rp_id`, `new_rp_id` | Le rpId avant et après la modification ; `null` signifie que chaque hôte de connexion est son propre rpId. |
| `status` | `active` pendant que la fenêtre est ouverte ; `completed` lorsqu'elle s'est terminée ; `completed_early` lorsqu'elle a été close plus tôt. |
| `ends_at` | Date prévue de fin de la fenêtre. |
| `completed_at`, `revoked_count`, `new_registration_count` | Renseignés à la clôture de la migration ; `null` tant qu'elle est `active`. |
| `fallback_enabled_by_migration` | `true` lorsqu'une méthode de connexion de secours a été activée pendant la fenêtre, parce que les clés d'accès étaient le seul premier facteur. |

## Erreurs

| HTTP | code | Quand |
|---|---|---|
| 400 | `unknown_field` | Le corps contient un champ inconnu. |
| 404 | `not_found` | La connexion n'existe pas ou appartient à un autre environnement. |
| 409 | `rp_id_migration_in_progress` | Une autre migration du rpId est en cours dans cet environnement. |
| 412 | `precondition_failed` | `If-Match` ne correspond pas à la version actuelle. |
| 422 | `validation_failed` | Un champ est manquant, trop long ou hors plage ; `new_rp_id` n'est pas un domaine personnalisé `active` de l'environnement ou est égal au rpId actuel ; `confirm_rp_id` diffère ; ou la connexion n'est pas une connexion par clé d'accès (`errors[].pointer` : `/new_rp_id`, `/confirm_rp_id`, `/migration_window_days`, `/connection_id`). |
| 428 | `precondition_required` | L'en-tête `If-Match` est absent. |
| 401 | `unauthenticated` | L'identifiant est absent, invalide ou révoqué. |
| 403 | `insufficient_permissions` | L'identifiant ne dispose pas de l'autorisation requise. |
| 429 | `rate_limited` | La limite de débit a été dépassée ; réessayez après le délai indiqué par `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez après le délai indiqué par `Retry-After`. |

## Exemple

```bash
curl -X POST "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b:change-rp-id" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H 'If-Match: "3"' \
  -H "Content-Type: application/json" \
  -d '{"new_rp_id":"login.example.com","confirm_rp_id":"login.example.com"}'
```

```bash
keenauth connections change-rp-id conn_01j9xp6q0r1s5t7v9w1x3y5z7b --if-match '"3"' --yes \
  --data '{"new_rp_id":"login.example.com","confirm_rp_id":"login.example.com"}'
```
