
# Crea o sostituisci la configurazione OIDC di una connessione

`PUT /v1/connections/{connection_id}/oidc` · autorizzazione `connections:write`

Crea o sostituisce completamente la configurazione relying party di una connessione OIDC enterprise.

- **Prima scrittura:** non inviare l'header `If-Match` e indica `sp_host` (un host attivo di questo ambiente). La callback `https://<sp_host>/sso/<connection_id>/callback` viene fissata da quel momento. La risposta è `201 Created`. Inviare `If-Match` quando non esiste ancora una configurazione fallisce con `412`.
- **Aggiornamento:** `If-Match` è obbligatorio. Senza di esso la richiesta fallisce con `428` e non viene scritto nulla, quindi una richiesta senza header non può mai sovrascrivere una configurazione esistente. Se la configurazione è cambiata dopo la tua lettura (o il valore non corrisponde) la richiesta fallisce con `412`. `*` corrisponde alla configurazione attuale. `sp_host` deve essere vuoto o corrispondere all'host memorizzato.

Il client secret è solo in scrittura: non viene mai restituito, registrato nei log o scritto nel log di audit. Quando aggiorni senza `client_secret`, il secret memorizzato viene mantenuto; `private_key_jwt` lo rimuove (la chiave di firma dell'ambiente firma l'asserzione del client). Un `issuer` modificato cancella il documento di discovery memorizzato; un `issuer` o un `client_id` modificati invalidano l'ultimo test di connessione superato. Inviare la stessa configurazione non scrive nulla. Le scritture vengono registrate nel log di audit come `connection.protocol_config_created` o `connection.oidc_config_updated` (solo i campi modificati; il secret compare solo come `client_secret_set`).

Su una connessione **attiva**, un aggiornamento che modifica `issuer` o `client_id` non viene applicato. L'intera richiesta (incluso un nuovo secret) diventa una [bozza di revisione](../connections/revisions.md): la risposta è `200 OK` con la configurazione live invariata, il suo `ETag` invariato e un campo `revision`. Testa la bozza con [Testa una connessione](../connections/test.md) e `revision_id`, poi [pubblicala](../connections/publish-revision.md). Gli altri aggiornamenti vengono applicati direttamente.

## Richiesta

| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
| `connection_id` | path | sì | ID della connessione OIDC enterprise (`conn_…`). |
| `If-Match` | header | in aggiornamento | L'`ETag` dell'ultima lettura o scrittura. In aggiornamento, se manca: `428`; se obsoleto: `412`. Non inviato alla prima scrittura. |
| `sp_host` | string | alla prima scrittura | Host attivo di questo ambiente (minuscolo). In aggiornamento vuoto o uguale all'host memorizzato. |
| `issuer` | string | sì | URL `https` assoluto senza query o fragment, massimo 512 byte. |
| `client_id` | string | sì | 1–255 byte, senza caratteri di controllo. |
| `client_auth_method` | string | sì | `private_key_jwt` (consigliato; nessun secret viene memorizzato), `client_secret_basic` o `client_secret_post`. |
| `client_secret` | string | no | Solo in scrittura, massimo 1024 byte. Mantenuto se omesso in aggiornamento. Non consentito con `private_key_jwt`. |
| `client_secret_expires_at` | string \| null | no | Quando il provider di identità fa scadere il secret (RFC 3339). Solo insieme a `client_secret`. |
| `provider_profile` | string | no | `entra`, `okta`, `google`, `keycloak`, `ping`, `onelogin`, `jumpcloud` o `generic` (predefinito). |
| `entra_tenant_id` | string | per `entra` | L'ID tenant di Microsoft Entra (UUID); solo per il profilo `entra`. |

## Risposta

`201 Created` alla prima scrittura, `200 OK` in caso di aggiornamento, con la configurazione (vedi [Ottieni la configurazione OIDC](get.md)) e il nuovo `ETag`. Il client secret non è nella risposta. Quando l'aggiornamento è diventato una bozza di revisione, il corpo contiene anche `revision` (la bozza) e la configurazione e l'`ETag` sono quelli live.

## Errori

| HTTP | code | Quando |
|---|---|---|
| 404 | `not_found` | La connessione non esiste in questo ambiente o non è una connessione enterprise. |
| 409 | `conflict` | La connessione non è una connessione OIDC, `sp_host` è diverso dall'host memorizzato, oppure un metodo con secret non ha un secret memorizzato o fornito. |
| 412 | `precondition_failed` | `If-Match` non corrisponde alla versione attuale, la configurazione è cambiata nel frattempo, oppure `If-Match` è stato inviato prima della prima scrittura. |
| 422 | `validation_failed` | Un campo non rispetta le regole sopra; `errors[]` punta al campo (`/issuer`, `/client_id`, `/client_auth_method`, `/client_secret`, `/client_secret_expires_at`, `/provider_profile`, `/entra_tenant_id`, `/sp_host`). |
| 428 | `precondition_required` | La configurazione esiste e l'header `If-Match` manca. |
| 400 | `unknown_field` | Il corpo contiene un campo sconosciuto. |
| 401 | `unauthenticated` | La credenziale manca, non è valida o è stata revocata. |
| 403 | `insufficient_permissions` | La credenziale non ha l'autorizzazione richiesta. |
| 429 | `rate_limited` | È stato superato il limite di frequenza; riprova dopo il periodo indicato in `Retry-After`. |
| 503 | `service_unavailable` | Una dipendenza è temporaneamente non disponibile; riprova dopo il periodo indicato in `Retry-After`. |

## Esempio

Tieni il secret in un file, non nella riga di comando (`oidc.json`):

```json
{"sp_host":"acme.eu1.keenauth.app","issuer":"https://idp.example.com","client_id":"keenauth-acme","client_auth_method":"client_secret_basic","client_secret":"<secret from the identity provider>"}
```

```bash
curl -X PUT "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b/oidc" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d @oidc.json
```

```bash
keenauth connections oidc put conn_01j9xp6q0r1s5t7v9w1x3y5z7b --data @oidc.json
keenauth connections oidc put conn_01j9xp6q0r1s5t7v9w1x3y5z7b --data @oidc-update.json --if-match '"6f1c…"'
```
