
# Enregistrer une clé d'accès

`POST /fapi/v1/me/passkeys` · appelé depuis l'hôte de connexion de l'environnement

Termine un enregistrement démarré avec [`POST /fapi/v1/me/passkeys/registration-options`](./registration-options) : vérifie la réponse du navigateur, stocke la clé d'accès ou la clé de sécurité, et la renvoie. L'utilisateur reçoit un e-mail de sécurité concernant la nouvelle méthode de connexion ; cet e-mail ne peut pas être désactivé. Nécessite le cookie `__Host-idp_session` de l'utilisateur authentifié ; si le cookie est absent, expiré ou révoqué, renvoie `401 unauthenticated`. Une application de première partie sur une autre origine peut à la place envoyer son jeton d'accès API front (`Authorization: DPoP <token>` avec une preuve DPoP ; voir [Jeton d'accès API front](/docs/api/fapi/front-api-token)).

Les règles de session sont celles de l'appel de démarrage : vérifiée au cours des 10 dernières minutes, et ouverte avec un second facteur si l'utilisateur en possède un.

## Requête

En-têtes :

| En-tête | Obligatoire | Description |
| --- | --- | --- |
| `Idp-Client` | oui | Identifiant du SDK. |
| `Origin` | oui | Doit être exactement `https://<hôte de connexion>`. |
| `Content-Type` | oui | `application/json`. |

Corps :

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `ceremony_id` | string | oui | Le `ceremony_id` de l'appel de démarrage. |
| `credential` | object | oui | Le résultat de `navigator.credentials.create` au format JSON (`PublicKeyCredential.toJSON()`), au maximum 16 Kio. |

## Réponse

`201 Created`, le nouvel authentificateur :

```json
{
  "id": "cred_01j9zzzzzzzzzzzzzzzzzzzzzz",
  "type": "passkey",
  "label": "iCloud Keychain",
  "status": "active",
  "synced": true,
  "created_at": "2026-10-12T09:00:00Z",
  "last_used_at": null
}
```

## Erreurs

Un enregistrement refusé n'est pas compté comme une tentative échouée ; recommencez avec un nouvel enregistrement.

| Statut | Code | Quand |
| --- | --- | --- |
| 400 | `malformed_request` | Le corps n'est pas un JSON valide. |
| 400 | `unknown_field` | Le corps contient un champ autre que `ceremony_id` et `credential`. |
| 401 | `unauthenticated` | Aucun cookie de session valide. |
| 401 | `step_up_required` | La session est trop ancienne ou un second facteur est requis ; vérifiez à nouveau avec les valeurs de l'en-tête `WWW-Authenticate`. |
| 403 | `origin_not_allowed` | `Origin` est absent ou incorrect. |
| 409 | `credential_already_registered` | Cet authentificateur est déjà enregistré dans l'environnement. |
| 409 | `credential_limit_reached` | L'utilisateur possède déjà le nombre maximal de clés d'accès et de clés de sécurité. |
| 413 | `payload_too_large` | Le corps est trop volumineux. |
| 415 | `unsupported_media_type` | `Content-Type` n'est pas `application/json`. |
| 422 | `validation_failed` | `/ceremony_id` : l'enregistrement est inconnu, expiré, déjà utilisé ou appartient à une autre session. `/credential` : la réponse est absente ou ne se vérifie pas. |
| 422 | `device_bound_passkey_required` | L'environnement n'accepte que les clés d'accès qui restent sur un seul appareil. |
| 422 | `aaguid_not_allowed` | L'environnement n'autorise pas ce modèle d'authentificateur. |
| 422 | `attestation_untrusted` | L'environnement exige une attestation de confiance, et celle-ci ne l'est pas. |

## Exemple

```bash
curl -X POST https://example.keenauth.app/fapi/v1/me/passkeys \
  -H "Idp-Client: my-app/1.0.0 (node/22.0.0)" \
  -H "Origin: https://example.keenauth.app" \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{"ceremony_id": "CQAAAAAAAAAAAAAAAAAAAA", "credential": {"id": "…", "rawId": "…", "type": "public-key", "response": {"clientDataJSON": "…", "attestationObject": "…"}}}'
```

## Données personnelles

Cet point de terminaison traite des données personnelles : identifiants. [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 aucun champ.
