
# Rotation des clés de signature

`POST /v1/signing-keys:rotate` · autorisation `signing-keys:write`

Lance une rotation de clé de signature immédiatement, en dehors du calendrier automatique.

- `mode: immediate` : l'étape de rotation régulière s'exécute aussitôt. La clé `next` préalablement publiée commence à signer, l'ancienne clé `active` reste `retired` pendant 7 jours et une nouvelle clé `next` est publiée. Si `next` utilise un algorithme différent de celui de la clé active (changement d'algorithme) et a été publiée il y a moins de 7 jours, l'appel échoue avec `409 next_key_too_young`.
- `mode: emergency` (compromission présumée d'une clé) : l'ancienne clé `active` est révoquée et disparaît du JWKS **immédiatement** ; `next` devient active et une nouvelle clé `next` est générée. `revoke_next: true` révoque aussi `next` et active une clé fraîchement générée, qui n'a jamais été publiée. `revoke_sessions: true` révoque en outre toutes les sessions et toutes les familles de jetons d'actualisation de l'environnement, de sorte que les utilisateurs doivent se reconnecter. `reason` est obligatoire.

## Clés de fédération

`use` peut aussi désigner une des clés de fédération de l'environnement : `saml_sp_signing` et `saml_sp_encryption` (les clés de signature et de chiffrement du fournisseur de service SAML, publiées dans vos métadonnées SP) ou `oidc_rp_signing` (la clé `private_key_jwt` des connexions OIDC d'entreprise, publiée à `/sso/jwks.json`). Ces clés sont toujours des RSA-3072 et tournent une fois par an automatiquement : une nouvelle clé `next` est publiée 30 jours avant de prendre le relais, et l'ancienne clé reste publiée pendant 30 jours après.

- `mode: immediate` rend active immédiatement la clé `next` préalablement publiée ; l'ancienne clé reste publiée 30 jours de plus (elle apparaît dans `retired_kids`). Sans clé `next` publiée, l'appel échoue avec `409 conflict` ; si la clé `next` a été publiée il y a moins de 7 jours, il échoue avec `409 next_key_too_young`.
- `mode: emergency` retire immédiatement la clé active des métadonnées ou du JWKS **et** détruit sa clé privée (`revoked_kids`). La clé `next` publiée devient active ; s'il n'y en a aucune, ou avec `revoke_next: true`, une nouvelle clé jamais publiée prend sa place. Les fournisseurs d'identité qui chargent vos métadonnées ou votre JWKS depuis leur URL prennent le changement en compte lors de leur prochaine actualisation. Les fournisseurs auxquels vous avez transmis les métadonnées ou le certificat à la main rejettent les connexions tant que vous n'avez pas téléversé le nouveau certificat ; dans ce cas, un événement webhook `connection.sp_certificate_rotation_started` est envoyé pour chaque connexion concernée.

Pour une clé de fédération, `next_kid` dans la réponse vaut `null`, `removed_kids` est vide et `revoke_sessions` n'est pas autorisé. Si l'environnement n'a jamais utilisé SAML ni `private_key_jwt`, il n'y a aucune clé à faire tourner et l'appel échoue avec `409 conflict`.

### Clés de connexion

Une connexion SAML peut avoir ses propres clés SP dédiées au lieu de celles de l'environnement. Pour les faire tourner, ajoutez `connection_id` (`conn_…`) avec `use: saml_sp_signing` ou `saml_sp_encryption`. Les mêmes modes, autorisations et règles s'appliquent, mais seul l'ensemble de clés de cette connexion change : les clés de l'environnement et celles des autres connexions restent inchangées, et l'événement `connection.sp_certificate_rotation_started` n'est envoyé que pour cette connexion. L'enregistrement d'audit désigne l'environnement comme cible et la connexion dans `metadata.connection_id`. Une connexion inconnue, ou appartenant à un autre environnement, échoue avec `404 not_found` ; une connexion qui utilise les clés de l'environnement échoue avec `409 connection_keys_not_dedicated` (faites tourner les clés de l'environnement sans `connection_id`). Sans `connection_id`, c'est l'ensemble de clés de l'environnement qui est renouvelé.

Le mode d'urgence exige, en plus de `signing-keys:write`, l'autorisation `signing-keys:emergency` accordée explicitement sur l'identifiant : seule une clé restreinte ou un client M2M portant cette autorisation peut l'appeler. Une clé secrète à accès complet (`idp_sk_…`) reçoit `403 insufficient_permissions` en mode d'urgence.

Les nouvelles clés de signature des jetons utilisent l'algorithme défini par la politique de l'environnement ([obtenir la politique](/docs/api/management/signing-keys/get-policy)). Une rotation réussie de la clé de signature des jetons émet l'événement webhook `signing_key.rotated` ou `signing_key.revoked` ; chaque rotation écrit un enregistrement d'audit de gestion. Ce point de terminaison appartient à la famille de limites de débit « émission de clés et de secrets ». Envoyez un `Idempotency-Key` : une nouvelle tentative après une erreur réseau renvoie alors le premier résultat au lieu de faire tourner la clé deux fois.

## Requête

Corps JSON (les champs inconnus sont rejetés avec `400 unknown_field`) :

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `Idempotency-Key` | en-tête | non | Recommandé. 16 à 64 caractères de `A-Z a-z 0-9 _ -`. |
| `mode` | chaîne | oui | `immediate` ou `emergency`. |
| `use` | chaîne | non | La clé à faire tourner. Par défaut `token_signing` (clé de signature des jetons d'accès et d'ID). Les clés de fédération sont `saml_sp_signing`, `saml_sp_encryption` et `oidc_rp_signing` (voir [Clés de fédération](#clés-de-fédération)). |
| `revoke_sessions` | booléen | non | Uniquement en urgence et `token_signing`. Révoque aussi toutes les sessions et tous les jetons d'actualisation. Par défaut `false`. |
| `revoke_next` | booléen | non | Uniquement en urgence. Révoque aussi la clé `next` publiée. Par défaut `false`. |
| `reason` | chaîne | urgence : oui | Uniquement en urgence. 1 à 512 caractères ASCII imprimables, par exemple un numéro d'incident. Ne pas y mettre de secrets ni de données personnelles. |
| `connection_id` | chaîne | non | `saml_sp_signing` et `saml_sp_encryption` uniquement. Une connexion SAML (`conn_…`) dotée de clés SP dédiées ; son ensemble de clés est renouvelé au lieu de celui de l'environnement (voir [Clés de connexion](#clés-de-connexion)). |

Avec `mode: immediate`, l'envoi de `revoke_sessions: true`, `revoke_next: true` ou d'un `reason` échoue avec `422` (`not_allowed`). Un `connection_id` avec `token_signing` ou `oidc_rp_signing` échoue de la même manière.

## Réponse

`200 OK` avec le résultat de la rotation. `activated_kid` est la clé qui signe désormais et `next_kid` la nouvelle clé `next` publiée (`null` pour une clé de fédération). `retired_kids` sont les clés qui ont cessé de signer et restent publiées (7 jours pour une clé de signature de jetons, 30 jours pour une clé de fédération) ; `revoked_kids` sont les clés retirées du JWKS par une rotation d'urgence ; `removed_kids` sont les clés retirées dont la fenêtre de 7 jours est échue et qui ont quitté le JWKS lors de la même étape.

```json
{
  "mode": "immediate",
  "use": "token_signing",
  "activated_kid": "ypeBEsobvcr6wjGzmiPcTaeG7_gUfE5yuYB3ha_uSLs",
  "next_kid": "GKw-c0PwFokMUQ6T-TUmEWnZ4_VlQ2Qpgw-vCTT0-OQ",
  "retired_kids": ["PiPoFgA5WUoziU9lZOGxNIu9egCI1CxKy3PurtWcAJ0"],
  "revoked_kids": [],
  "removed_kids": ["Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y"],
  "revoke_sessions": false
}
```

## Erreurs

| HTTP | code | Quand |
|---|---|---|
| 400 | `unknown_field` | Le corps contient un champ inconnu. |
| 400 | `malformed_request` | Le corps n'est pas du JSON valide, ou l'en-tête `Idempotency-Key` est mal formé ou répété. |
| 403 | `insufficient_permissions` | L'identifiant ne dispose pas de `signing-keys:write`, ou le mode d'urgence a été demandé sans `signing-keys:emergency` accordée explicitement. |
| 404 | `not_found` | `connection_id` ne désigne aucune connexion SAML de cet environnement. |
| 409 | `connection_keys_not_dedicated` | `connection_id` désigne une connexion qui utilise les clés SP de l'environnement. |
| 409 | `next_key_too_young` | Un changement d'algorithme est en attente et la clé `next` a été publiée il y a moins de 7 jours, ou (clé de fédération, `immediate`) la clé `next` a été publiée il y a moins de 7 jours. |
| 409 | `conflict` | L'environnement n'a aucune clé `next` publiée, n'a aucune clé active de la fédération `use`, ou la clé de fédération précédente est encore dans sa période de chevauchement de 30 jours. |
| 415 | `unsupported_media_type` | Le type de contenu n'est pas `application/json`. |
| 422 | `validation_failed` | Un champ est manquant ou invalide ; le pointeur désigne le champ, par exemple `/reason`. |
| 422 | `idempotency_key_reuse` | La `Idempotency-Key` a déjà été utilisée avec un corps différent. |
| 501 | `not_implemented` | L'opération n'est pas encore disponible dans ce déploiement. |
| 401 | `unauthenticated` | L'identifiant est absent, invalide ou révoqué. |
| 429 | `rate_limited` | La limite de débit a été dépassée ; réessayez après la période `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez après la période `Retry-After`. |

## Exemple

Rotation régulière :

```bash
curl -X POST "https://api.eu.keenauth.com/v1/signing-keys:rotate" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"mode":"immediate"}'
```

Rotation d'urgence avec une clé restreinte qui accorde `signing-keys:write` et `signing-keys:emergency` :

```bash
curl -X POST "https://api.eu.keenauth.com/v1/signing-keys:rotate" \
  -H "Authorization: Bearer $KEENAUTH_EMERGENCY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"mode":"emergency","revoke_sessions":true,"reason":"INC-2041 key exposure"}'
```

Rotation d'urgence de la clé de signature SP SAML, avec révocation aussi de la clé `next` publiée :

```bash
curl -X POST "https://api.eu.keenauth.com/v1/signing-keys:rotate" \
  -H "Authorization: Bearer $KEENAUTH_EMERGENCY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"mode":"emergency","use":"saml_sp_signing","revoke_next":true,"reason":"INC-2042 SP key exposure"}'
```

Rotation d'urgence de la clé de signature SP SAML dédiée d'une connexion :

```bash
curl -X POST "https://api.eu.keenauth.com/v1/signing-keys:rotate" \
  -H "Authorization: Bearer $KEENAUTH_EMERGENCY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"mode":"emergency","use":"saml_sp_signing","connection_id":"conn_01h2xcejqtf2nbrexx3vqjhp41","reason":"INC-2043 connection key exposure"}'
```
