
# Créer une connexion

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

Enregistre une nouvelle connexion dans l'environnement. Les connexions qui nécessitent une configuration de protocole (`social`, `enterprise`) démarrent `inactive` ; activez-les explicitement avec `:activate`. Une connexion `enterprise` ne peut pas être créée `active` : une nouvelle connexion ne peut pas encore avoir de test de connexion réussi. Les paramètres ne doivent pas contenir de secrets. Un environnement peut contenir au maximum 100 connexions et 20 connexions sociales génériques (`oidc_generic`, `oauth2_generic`), et une organisation au maximum 20 connexions.

## Requête

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

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `key` | string | oui | Clé de configuration stable, `^[a-z0-9_-]{1,64}$`, unique dans l'environnement, immuable. |
| `type` | string | oui | `database`, `passwordless`, `passkey`, `social` ou `enterprise`. Immuable. |
| `strategy` | string | oui | Stratégie pour le type, par exemple `password`, `email_otp`, `google`, `saml`. Immuable. |
| `name` | string | oui | 1 à 128 caractères, unique dans l'environnement. |
| `display_name` | string | non | 1 à 128 caractères affichés sur les écrans de connexion. |
| `status` | string | non | `active` ou `inactive`. Par défaut `active` pour `database`, `passwordless`, `passkey` et `inactive` pour `social`, `enterprise`. |
| `org_id` | string | non | Organisation propriétaire (`org_…`), `enterprise` uniquement. Omis : une connexion d'environnement. Immuable. |
| `allowed_email_domains` | array of strings | non | Domaines e-mail acheminés vers cette connexion par la découverte de domaine d'origine : étiquette A IDNA, minuscules (par exemple `xn--bcher-kva.example`), uniques, au maximum 100 ; non vide uniquement pour `enterprise`. Pour une connexion d'organisation, chaque domaine doit être un domaine vérifié de l'organisation, et une connexion d'organisation `active` en nécessite au moins un. |
| `allow_external_domains` | boolean | non | Autorise aussi la connexion des utilisateurs dont le domaine e-mail n'est pas listé. `enterprise` uniquement ; valeur par défaut `false`. |
| `jit_mode` | string | non | Provisionnement à la volée : `create` crée l'utilisateur à sa première connexion, `create_and_update` met aussi à jour le profil à partir du fournisseur d'identité, `off` exige un compte existant. `enterprise` uniquement. Par défaut `create_and_update` pour une connexion d'environnement et `off` pour une connexion d'organisation. |
| `email_trust` | boolean | non | Fait confiance à l'adresse e-mail affirmée par le fournisseur d'identité pour la liaison automatique de compte et le provisionnement à la volée. `enterprise` uniquement ; valeur par défaut `false`. Pour une connexion d'organisation, `true` nécessite un `allowed_email_domains` non vide dans lequel chaque domaine est un domaine vérifié de l'organisation. |
| `default_role_ids` | array of strings | non | Rôles d'environnement (`rol_…`, uniques, au maximum 10) accordés au membre créé par une connexion à la volée, en plus du rôle par défaut de l'environnement et des correspondances de groupes de la connexion. Uniquement pour une connexion `enterprise` d'organisation. Chaque rôle doit être un rôle d'environnement non privilégié de cet environnement ; un rôle d'un autre environnement, un rôle d'organisation, un rôle privilégié ou un rôle inexistant est rejeté. Un rôle supprimé ou rendu privilégié ultérieurement est ignoré lors de la connexion. |
| `trust_idp_mfa` | boolean | non | Accepte l'authentification multifacteur affirmée par le fournisseur d'identité (contexte d'authentification SAML, `amr`/`acr` OIDC) comme preuve MFA de la session. `enterprise` uniquement ; valeur par défaut `false`. |
| `settings` | object | non | Paramètres sans secrets, jusqu'à 32 KiB. Les clés ou valeurs qui ressemblent à des secrets sont rejetées. |
| `Idempotency-Key` | header | non | Clé facultative (16 à 64 caractères) qui rend sûre la relance d'une requête. |

## Réponse

`201 Created` avec la connexion et un en-tête `ETag` contenant sa version.

```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"
}
```

## Paramètres de clé d'accès

Pour `type: "passkey"`, l'objet `settings` n'accepte que les clés ci-dessous. Toute autre clé, un mauvais type ou une valeur hors plage est rejeté avec `422 validation_failed` et un `errors[].pointer` tel que `/settings/max_credentials_per_user`. Une valeur `null` signifie la valeur par défaut. Les erreurs de forme sont signalées avant les erreurs de plan.

| Clé | Type | Remarques |
|---|---|---|
| `rp_id` | string | Absent, `null` ou vide : chaque hôte de connexion est son propre rpId. Sinon, le nom d'hôte d'un domaine personnalisé `active` de l'environnement (minuscules, étiquette A IDNA) ; toute autre valeur donne `422 validation_failed` (`/settings/rp_id`). Une fois que l'environnement contient des clés d'accès, modifiez-le avec [Modifier le rpId de la clé d'accès](change-rp-id.md). |
| `rp_name` | string | Jusqu'à 128 caractères. |
| `passkey_first_factor_enabled`, `security_key_second_factor_enabled` | boolean | Par défaut `true`. |
| `user_verification` | string | `preferred` (par défaut) ou `required`. |
| `max_credentials_per_user` | integer | 1 à 20, par défaut 20 ; les fractions sont rejetées. |
| `require_device_bound_passkeys` | boolean | Soumis au plan : `true` nécessite Startup. |
| `attestation_required` | boolean | Soumis au plan : `true` nécessite Enterprise. |
| `aaguid_allowlist`, `aaguid_blocklist` | array of UUID strings | Au maximum 500 entrées uniques chacune (les erreurs pointent vers `/settings/<key>/<index>`). Soumis au plan : une liste non vide nécessite Enterprise. |
| `related_origins` | array of strings | Origines `https://host[:port]`. Soumis au plan : une liste non vide nécessite Enterprise. |
| `passkey_enrollment_prompt` | string | `off` ou `after_login` (par défaut). |

Écrire une valeur non par défaut d'une clé soumise au plan échoue avec `403 plan_feature_unavailable` et les membres `feature` et `required_plan`. Tant que les droits du plan ne sont pas disponibles, ces clés ne peuvent être définies dans aucun environnement ; écrire une valeur par défaut (`false`, `[]`, `null`) ou supprimer la clé est toujours autorisé. Lorsque la fonctionnalité est disponible, chaque entrée de `related_origins` doit être un domaine personnalisé vérifié et actif de l'environnement, sinon la requête échoue avec `422 related_origin_not_verified`.

## Erreurs

| HTTP | code | Quand |
|---|---|---|
| 400 | `unknown_field` | Le corps contient un champ inconnu. |
| 403 | `quota_exceeded` | Une limite de connexions de l'environnement ou de l'organisation (`org_id`) est atteinte. |
| 409 | `conflict` | Une connexion avec la même `key` ou le même `name` existe. |
| 409 | `connection_test_required` | La requête crée une connexion `enterprise` avec `status: active` ; rien n'est écrit. Créez-la `inactive`, testez sa connexion, puis activez-la avec `:activate`. |
| 415 | `unsupported_media_type` | Le type de contenu n'est pas `application/json`. |
| 422 | `validation_failed` | Un champ est manquant ou invalide ; `errors[].pointer` le désigne (par exemple `/settings/client_secret` pour les paramètres ressemblant à des secrets). |
| 422 | `related_origin_not_verified` | Une origine liée n'est pas un domaine personnalisé vérifié de l'environnement. |
| 403 | `plan_feature_unavailable` | Le plan n'inclut pas un paramètre que vous avez défini (membres `feature`, `required_plan`), par exemple `attestation_required`. |
| 401 | `unauthenticated` | L'identifiant est manquant, 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 la période `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez après la période `Retry-After`. |

## Exemple

```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"}'
```
