
# パスキーを登録する

`POST /fapi/v1/me/passkeys` · 環境のサインインホストから呼び出されます

[`POST /fapi/v1/me/passkeys/registration-options`](./registration-options) で開始した登録を完了します。ブラウザーの応答を検証し、パスキーまたはセキュリティキーを保存して、そのデータを返します。ユーザーには、新しいサインイン方法に関するセキュリティメールが届きます。このメールは無効にできません。認証済みユーザーの `__Host-idp_session` Cookie が必要です。Cookie がない、期限切れ、または取り消されている場合は `401 unauthenticated` を返します。別オリジンのファーストパーティアプリは、代わりに DPoP 証明書付きのフロント API アクセストークン（`Authorization: DPoP <token>`。詳細は [フロント API アクセストークン](/docs/api/fapi/front-api-token) を参照）を送信できます。

セッションのルールは開始時の呼び出しと同じです。直近10分以内に検証されていること、そしてユーザーが第2要素を持つ場合は第2要素を使ってセッションを開いていることが必要です。

## リクエスト

ヘッダー:

| ヘッダー | 必須 | 説明 |
| --- | --- | --- |
| `Idp-Client` | はい | SDK の識別子。 |
| `Origin` | はい | 正確に `https://<sign-in host>` である必要があります。 |
| `Content-Type` | はい | `application/json`。 |

ボディ:

| フィールド | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `ceremony_id` | string | はい | 開始呼び出しの `ceremony_id`。 |
| `credential` | object | はい | `navigator.credentials.create` の結果を JSON 化したもの（`PublicKeyCredential.toJSON()`）。16 KiB まで。 |

## レスポンス

`201 Created` で、新しい認証機能を返します:

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

## エラー

拒否された登録は失敗回数に含まれません。新しい登録を作成して、やり直してください。

| ステータス | コード | 発生条件 |
| --- | --- | --- |
| 400 | `malformed_request` | ボディが有効な JSON ではありません。 |
| 400 | `unknown_field` | ボディに `ceremony_id` と `credential` 以外のフィールドがあります。 |
| 401 | `unauthenticated` | 有効なセッション Cookie がありません。 |
| 401 | `step_up_required` | セッションが古い、または第2要素が必要です。`WWW-Authenticate` ヘッダーの値を使って再検証してください。 |
| 403 | `origin_not_allowed` | `Origin` がない、または誤っています。 |
| 409 | `credential_already_registered` | この認証機能は、環境内にすでに登録されています。 |
| 409 | `credential_limit_reached` | ユーザーは、パスキーとセキュリティキーの上限数にすでに達しています。 |
| 413 | `payload_too_large` | ボディが大きすぎます。 |
| 415 | `unsupported_media_type` | `Content-Type` が `application/json` ではありません。 |
| 422 | `validation_failed` | `/ceremony_id`: 登録が不明、期限切れ、使用済み、または別のセッションのものです。`/credential`: 応答がない、または検証に失敗しました。 |
| 422 | `device_bound_passkey_required` | 環境では、1台のデバイスに留まるパスキーのみが許可されています。 |
| 422 | `aaguid_not_allowed` | 環境では、この認証機器のモデルは許可されていません。 |
| 422 | `attestation_untrusted` | 環境では信頼された証明が必要ですが、この証明は信頼されていません。 |

## 例

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

## 個人データ

このエンドポイントは個人データを扱います。認証情報が対象です。[KeenAuth API における個人データ](/docs/policies/personal-data)では、保存される内容、保存期間、削除方法を説明しています。いずれのフィールドにも、特別な種類の個人データ（健康、生体情報、宗教、政治的意見、性的指向）を送信しないでください。
