
# Crea una connessione

`POST /v1/connections` · autorizzazione `connections:write`

Registra una nuova connessione nell'ambiente. Le connessioni che richiedono una configurazione del protocollo (`social`, `enterprise`) iniziano come `inactive`; attivale esplicitamente con `:activate`. Una connessione `enterprise` non può essere creata come `active`: una nuova connessione non può ancora avere un accesso di prova riuscito. Le impostazioni non devono contenere segreti. Un ambiente può contenere al massimo 100 connessioni e 20 connessioni social generiche (`oidc_generic`, `oauth2_generic`), e un'organizzazione al massimo 20 connessioni.

## Richiesta

Corpo JSON (i campi sconosciuti vengono rifiutati con `400 unknown_field`):

| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
| `key` | stringa | sì | Chiave di configurazione stabile, `^[a-z0-9_-]{1,64}$`, unica nell'ambiente, non modificabile. |
| `type` | stringa | sì | `database`, `passwordless`, `passkey`, `social` o `enterprise`. Non modificabile. |
| `strategy` | stringa | sì | Strategia per il tipo, ad esempio `password`, `email_otp`, `google`, `saml`. Non modificabile. |
| `name` | stringa | sì | Da 1 a 128 caratteri, unica nell'ambiente. |
| `display_name` | stringa | no | Da 1 a 128 caratteri mostrati nelle schermate di accesso. |
| `status` | stringa | no | `active` o `inactive`. Il valore predefinito è `active` per `database`, `passwordless`, `passkey` e `inactive` per `social`, `enterprise`. |
| `org_id` | stringa | no | Organizzazione proprietaria (`org_…`), solo per `enterprise`. Se omesso: una connessione di ambiente. Non modificabile. |
| `allowed_email_domains` | array di stringhe | no | Domini email instradati a questa connessione tramite home realm discovery: etichetta A IDNA, minuscola (ad esempio `xn--bcher-kva.example`), unica, al massimo 100; non vuota solo per `enterprise`. In una connessione di organizzazione ogni dominio deve essere un dominio verificato dell'organizzazione, e una connessione di organizzazione `active` ne richiede almeno uno. |
| `allow_external_domains` | booleano | no | Consente anche l'accesso agli utenti il cui dominio email non è nell'elenco. Solo `enterprise`; predefinito `false`. |
| `jit_mode` | stringa | no | Provisioning just-in-time: `create` crea l'utente al primo accesso, `create_and_update` aggiorna anche il profilo dal provider di identità, `off` richiede un account esistente. Solo `enterprise`. Il valore predefinito è `create_and_update` per una connessione di ambiente e `off` per una connessione di organizzazione. |
| `email_trust` | booleano | no | Considera attendibile l'indirizzo email dichiarato dal provider di identità per il collegamento automatico degli account e il provisioning just-in-time. Solo `enterprise`; predefinito `false`. In una connessione di organizzazione `true` richiede un `allowed_email_domains` non vuoto in cui ogni dominio è un dominio verificato dell'organizzazione. |
| `default_role_ids` | array di stringhe | no | Ruoli dell'ambiente (`rol_…`, unici, al massimo 10) assegnati all'appartenenza creata da un accesso just-in-time, oltre al ruolo predefinito dell'ambiente e alle mappature di ruolo di gruppo della connessione. Solo per una connessione `enterprise` di organizzazione. Ogni ruolo deve essere un ruolo non privilegiato di questo ambiente; un ruolo di un altro ambiente, un ruolo di organizzazione, un ruolo privilegiato o un ruolo mancante viene rifiutato. Un ruolo eliminato o reso privilegiato in seguito viene ignorato durante l'accesso. |
| `trust_idp_mfa` | booleano | no | Accetta l'autenticazione a più fattori dichiarata dal provider di identità (contesto di autenticazione SAML, `amr`/`acr` di OIDC) come prova MFA della sessione. Solo `enterprise`; predefinito `false`. |
| `settings` | oggetto | no | Impostazioni senza segreti, fino a 32 KiB. Chiavi o valori che sembrano segreti vengono rifiutati. |
| `Idempotency-Key` | intestazione | no | Chiave facoltativa (da 16 a 64 caratteri) che rende sicura la ripetizione di una richiesta. |

## Risposta

`201 Created` con la connessione e un'intestazione `ETag` che contiene la sua versione.

```json
{
  "id": "conn_0k3v8m1q2x9dz4h7s5t6w0y1ab",
  "key": "google",
  "type": "social",
  "strategy": "google",
  "name": "Google",
  "display_name": "Sign in with Google",
  "status": "inactive",
  "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"
}
```

## Impostazioni passkey

Per `type: "passkey"` l'oggetto `settings` accetta solo le chiavi sotto indicate. Qualsiasi altra chiave, un tipo errato o un valore fuori intervallo viene rifiutato con `422 validation_failed` e un `errors[].pointer` come `/settings/max_credentials_per_user`. Un valore `null` indica il valore predefinito. Gli errori di forma vengono segnalati prima di quelli di piano.

| Chiave | Tipo | Note |
|---|---|---|
| `rp_id` | stringa | Assente, `null` o vuota: ogni host di accesso è il proprio rpId. Altrimenti il nome host di un dominio personalizzato `active` dell'ambiente (minuscolo, etichetta A IDNA); qualsiasi altro valore dà `422 validation_failed` (`/settings/rp_id`). Una volta che l'ambiente ha passkey, modificala con [Modifica del passkey rpId](change-rp-id.md). |
| `rp_name` | stringa | Fino a 128 caratteri. |
| `passkey_first_factor_enabled`, `security_key_second_factor_enabled` | booleano | Predefinito `true`. |
| `user_verification` | stringa | `preferred` (predefinito) o `required`. |
| `max_credentials_per_user` | intero | Da 1 a 20, predefinito 20; le frazioni vengono rifiutate. |
| `require_device_bound_passkeys` | booleano | Vincolato al piano: `true` richiede Startup. |
| `attestation_required` | booleano | Vincolato al piano: `true` richiede Enterprise. |
| `aaguid_allowlist`, `aaguid_blocklist` | array di stringhe UUID | Al massimo 500 voci uniche ciascuno (gli errori puntano a `/settings/<chiave>/<indice>`). Vincolato al piano: un elenco non vuoto richiede Enterprise. |
| `related_origins` | array di stringhe | Origini `https://host[:port]`. Vincolato al piano: un elenco non vuoto richiede Enterprise. |
| `passkey_enrollment_prompt` | stringa | `off` o `after_login` (predefinito). |

Scrivere un valore non predefinito di una chiave vincolata al piano fallisce con `403 plan_feature_unavailable` e i membri `feature` e `required_plan`. Finché i diritti del piano non sono disponibili, queste chiavi non possono essere impostate in nessun ambiente; scrivere un valore predefinito (`false`, `[]`, `null`) o rimuovere la chiave è sempre consentito. Quando la funzione è disponibile, ogni voce di `related_origins` deve essere un dominio personalizzato verificato e attivo dell'ambiente, altrimenti la richiesta fallisce con `422 related_origin_not_verified`.

## Errori

| HTTP | code | Quando |
|---|---|---|
| 400 | `unknown_field` | Il corpo contiene un campo sconosciuto. |
| 403 | `quota_exceeded` | È stato raggiunto un limite di connessioni dell'ambiente o dell'organizzazione (`org_id`). |
| 409 | `conflict` | Esiste già una connessione con la stessa `key` o `name`. |
| 409 | `connection_test_required` | La richiesta crea una connessione `enterprise` con `status: active`; non viene scritto nulla. Creala `inactive`, testa il suo accesso, poi attivala con `:activate`. |
| 415 | `unsupported_media_type` | Il tipo di contenuto non è `application/json`. |
| 422 | `validation_failed` | Un campo manca o non è valido; `errors[].pointer` lo indica (ad esempio `/settings/client_secret` per impostazioni simili a segreti). |
| 422 | `related_origin_not_verified` | Un'origine correlata non è un dominio personalizzato verificato dell'ambiente. |
| 403 | `plan_feature_unavailable` | Il piano non include un'impostazione che hai scelto (membri `feature`, `required_plan`), ad esempio `attestation_required`. |
| 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 richieste; 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

```bash
curl -X POST https://api.eu.keenauth.com/v1/connections \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key":"google","type":"social","strategy":"google","name":"Google"}'
```
