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 : 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).

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 :

{
  "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

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 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.