1. Docs
  2. API Reference
  3. Enroll a passkey to complete a sign-in that required a factor

Enroll a passkey to complete a sign-in that required a factor

POST/v1/auth/login/mfa-enroll/webauthn/verify

Completes a sign-in that answered requires_mfa_enrollment by verifying the attestation response against the nonce sealed in enrollment_token and storing the passkey under label. The session then issues bound to the Account that required the factor, with amr extended by mfa and hwk and the ten recovery codes shown this once. 400 when the attestation fails to verify, 401 for a bad token. Rate-limited to 10 requests per 10 minutes.

Request body

application/json

enrollment_tokenstring Required

The sealed enrollment_token from `/v1/auth/login/mfa-enroll/webauthn/options`.

responseobject Required

The PublicKeyCredential JSON returned by `navigator.credentials.create()`.

labelstring Optional

User-facing nickname for the factor (default "Passkey").

max length 80

rememberboolean Optional

Keep the session on this device: persist the refresh cookie across browser restarts, as the `remember` flag on `/v1/auth/login` does. Default false.

Responses

application/json

  • dataLoginResponseDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

Rate limit

10 requests per 10mPer caller: the signed-in user for a bearer token; for an API key, the key and the end user's address when a backend forwards it, otherwise the client address

Returned object

Request
curl -X POST "https://auth.canopy-io.com/v1/auth/login/mfa-enroll/webauthn/verify" \
  -H "Content-Type: application/json" \
  -d '{
    "enrollment_token": "string",
    "response": {},
    "label": "string",
    "remember": false
  }'
Response
{
  "data": {
    "mfa_enrollment_pending": false,
    "grace_expires_at": "2026-04-20T12:00:00.000Z",
    "requires_mfa_enrollment": false,
    "mfa_enrollment": {
      "enrollment_token": "string",
      "available_factors": [
        "totp"
      ],
      "totp": {
        "otpauth_uri": "string",
        "manual_entry_key": "string"
      }
    },
    "requires_account_selection": false,
    "requires_mfa_challenge": false,
    "mfa_challenge": {
      "challenge_token": "string",
      "available_factors": [
        "totp"
      ],
      "expires_at": "2026-04-20T12:00:00.000Z"
    },
    "device_remembered": false,
    "recovery_codes": [
      "string"
    ],
    "expires_in": 0,
    "user": {
      "id": "string",
      "email": "string",
      "first_name": "string",
      "last_name": "string"
    },
    "access_token": "string",
    "token_type": "string",
    "default_environment_slug": "string",
    "accounts": [
      {
        "account_id": "string",
        "account_name": "string",
        "account_slug": "string",
        "account_role": "string",
        "applications": [
          {
            "id": "string",
            "name": "string",
            "slug": "string"
          }
        ]
      }
    ],
    "pending_account_creation": false
  }
}
Related endpoints
POSTAnswer the sign-in challenge with an authenticator app code
POSTAnswer the sign-in challenge with a recovery code
POSTGet passkey assertion options for the sign-in challenge
POSTAnswer the sign-in challenge with a passkey
POSTEnroll an authenticator app to complete a sign-in that required one
POSTGet passkey creation options to complete a sign-in that required a factor
Was this page helpful?

Tell us how we can improve this guide.