
# Ruota una chiave API

`POST /v1/api-keys/{key_id}:rotate` · autorizzazione `api-keys:write` · `Idempotency-Key` facoltativo

Ruota una chiave: crea una NUOVA chiave con lo stesso nome, tipo, autorizzazioni e `allowed_cidrs`, e la restituisce. La vecchia chiave resta valida per `overlap_hours`, poi smette di funzionare.

- **Nuova chiave.** La risposta descrive la nuova chiave; `rotated_from` è l'id della vecchia chiave e `key` contiene la chiave in chiaro una sola volta (`Cache-Control: no-store`). Distribuiscila, poi lascia scadere la vecchia chiave.
- **Sovrapposizione.** La vecchia chiave riceve `revoked_at` nel futuro e `revoke_reason: rotated`; con `overlap_hours: 0` viene revocata immediatamente.
- **Nessuna escalation.** Una chiave non può ruotare una chiave con autorizzazioni superiori alle proprie, e una chiave `restricted` non può ruotare una chiave `secret`. La nuova chiave non può scadere dopo la chiave che la richiede, anche quando una chiave ruota se stessa (per estendere una durata usa la dashboard), e una chiave con `allowed_cidrs` può ruotare solo chiavi limitate a reti contenute nelle proprie. Una chiave creata nella dashboard, e ogni chiave ruotata da essa, può essere ruotata solo da se stessa o nella dashboard (`permission_escalation`). La nuova chiave mantiene il `created_by` della vecchia; la chiave che esegue la rotazione viene registrata nel log di audit.
- **Replay idempotente.** Un replay con lo stesso `Idempotency-Key` omette `key` e restituisce `secret_redacted: true`.

## Richiesta

| Parametro | In | Descrizione |
|---|---|---|
| `key_id` | path | Id della chiave API (`key_…`). |

Corpo:

Il corpo è facoltativo; senza di esso si applicano tutti i valori predefiniti.

| Campo | Tipo | Descrizione |
|---|---|---|
| `overlap_hours` | integer | Facoltativo, da 0 a 168, predefinito 24. Per quante ore la vecchia chiave resta valida. |
| `expires_at` | string (date-time) | Facoltativo. Scadenza della NUOVA chiave; predefinita a ora + 365 giorni, al massimo la scadenza della chiave che la richiede e al massimo 730 giorni. |

## Risposta

`200 OK` con `Cache-Control: no-store`. L'oggetto della NUOVA chiave più `key`.

```json
{
  "id": "key_0000000000000000000000001z",
  "name": "ci",
  "type": "restricted",
  "permissions": ["users:read"],
  "allowed_cidrs": [],
  "last4": "xxxx",
  "created_by": "key_…",
  "created_at": "2026-10-01T10:00:00Z",
  "expires_at": "2027-10-01T10:00:00Z",
  "last_used_at": null,
  "last_used_ip": null,
  "rotated_from": "key_…",
  "revoked_at": null,
  "revoke_reason": null,
  "key": "<shown once>"
}
```

## Errori

| HTTP | `code` | Quando |
|---|---|---|
| 401 | `unauthenticated` | La chiave manca, non è valida o è revocata. |
| 403 | `insufficient_permissions` | La chiave non ha l'autorizzazione richiesta. |
| 403 | `permission_escalation` | La richiesta darebbe a una chiave più autorizzazioni, un intervallo di rete più ampio o una scadenza più lontana di quelle della chiave che la richiede, una chiave `restricted` tenta di creare, ruotare o revocare oltre le proprie autorizzazioni, oppure un'altra chiave tenta di ruotare o revocare una chiave creata nella dashboard. |
| 404 | `not_found` | La chiave non esiste in questo ambiente. |
| 409 | `conflict` | La chiave è già revocata, scaduta o già ruotata (non attiva). |
| 409 | `api_key_limit_reached` | L'ambiente ha già il massimo di 50 chiavi attive. |
| 422 | `validation_failed` | Il corpo non è valido: `overlap_hours` fuori da 0–168 oppure `expires_at` nel passato o più di 730 giorni nel futuro. |

## Esempio

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