
# Lier une identité fédérée à un utilisateur

`POST /v1/users/{user_id}/identities` · autorisation `users:write`

Lie une identité fédérée (le sujet externe d'une connexion sociale, SAML ou OIDC) à l'utilisateur, afin que celui-ci puisse se connecter via cette connexion. `linked_via` vaut toujours `admin_api`. La connexion doit être une connexion activée de cet environnement dont le type correspond à `type`. Si la même identité est déjà liée à cet utilisateur ou à un autre, la requête échoue avec `409` et le propriétaire n'est pas révélé. Le sujet externe est une donnée personnelle : il est stocké chiffré et n'est jamais renvoyé, et l'enregistrement d'audit de gestion `user.identity_linked` (acteur : la clé d'API) ne le contient pas. La fusion de deux utilisateurs (`source_user_id`) n'est pas disponible ; un champ inconnu renvoie `400 unknown_field`.

## Requête

| Paramètre | Dans | Requis | Description |
|---|---|---|---|
| `user_id` | path | oui | Identifiant de l'utilisateur, préfixé `usr_`. |

| Champ | Type | Requis | Description |
|---|---|---|---|
| `type` | string | oui | `social`, `saml` ou `oidc` ; doit correspondre à la connexion (`social` pour une connexion sociale, `saml`/`oidc` pour une connexion entreprise de la même stratégie). |
| `connection_id` | string | oui | Identifiant de la connexion, préfixé `conn_`. |
| `subject` | string | oui | Sujet externe auprès du fournisseur d'identité (OIDC `sub`, SAML NameID), au maximum 1024 octets en UTF-8. |

## Réponse

`201 Created` avec la nouvelle identité, au format renvoyé par `GET /v1/users/{user_id}/identities`.

```json
{
  "id": "idn_0a1b2c3d4e5f6g7h8j9k0m1n2r",
  "type": "oidc",
  "connection_id": "conn_0a1b2c3d4e5f6g7h8j9k0m1n2s",
  "provider": null,
  "linked_via": "admin_api",
  "created_at": "2026-01-15T09:30:00Z"
}
```

## Erreurs

Toute erreur est un corps `application/problem+json` avec un `code` stable.

| HTTP | `code` | Cas |
|---|---|---|
| 400 | `malformed_request`, `unknown_field` | Le corps n'est pas du JSON valide ou contient un champ inconnu. |
| 409 | `conflict` | L'identité est déjà liée à un utilisateur (`errors[]` : `identity_already_linked`), ou l'utilisateur a atteint la limite d'identités par utilisateur (`errors[]` : `identity_limit_reached`). |
| 415 | `unsupported_media_type` | Le corps a été envoyé sans `Content-Type: application/json`. |
| 422 | `validation_failed` | Un champ est manquant ou invalide (`/type`, `/connection_id`, `/subject`), ou la connexion n'est pas une connexion activée de cet environnement correspondant à `type` (`errors[]` : `/connection_id`, `connection_unavailable`). |
| 404 | `not_found` | L'utilisateur n'existe pas dans cet environnement, est en cours de suppression, ou l'identifiant est mal formé. |
| 401 | `unauthenticated` | La clé d'API est absente, invalide ou révoquée. |
| 403 | `insufficient_permissions` | La clé ne dispose pas de l'autorisation `users:write`. |
| 429 | `rate_limited` | La limite de débit a été dépassée ; respectez `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez plus tard. |

## Exemple

```bash
curl -X POST https://api.eu.keenauth.com/v1/users/usr_0a1b2c3d4e5f6g7h8j9k0m1n2p/identities \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "oidc", "connection_id": "conn_0a1b2c3d4e5f6g7h8j9k0m1n2s", "subject": "248289761001"}'
```

## Données personnelles

Cet endpoint traite des données personnelles : des identités liées. [Données personnelles dans les API KeenAuth](/docs/policies/personal-data) décrit ce qui est stocké, la durée de conservation et la manière dont elles sont supprimées. N'envoyez pas de catégories particulières de données personnelles (santé, données biométriques, religion, opinions politiques, orientation sexuelle) dans un champ quelconque.
