1. Docs
  2. API Reference
  3. Enroll an authenticator app to complete a sign-in that required one

Enroll an authenticator app to complete a sign-in that required one

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

Completes a sign-in that answered requires_mfa_enrollment by verifying the 6-digit code against the secret sealed in enrollment_token and storing the authenticator-app factor under label. The session then issues bound to the Account that required the factor, with amr extended by mfa and otp and the ten recovery codes shown this once; remember decides whether the refresh cookie persists. Public (the token is the credential); 400 for a wrong code, 401 for a token that is missing, expired or tampered. Rate-limited to 10 requests per 10 minutes.

Request body

application/json

enrollment_tokenstring Required

The sealed enrollment_token from the sign-in's `mfa_enrollment` continuation.

codestring Required

The 6-digit code from the authenticator app.

labelstring Optional

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

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/totp/verify" \
  -H "Content-Type: application/json" \
  -d '{
    "enrollment_token": "string",
    "code": "123456",
    "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
POSTGet passkey creation options to complete a sign-in that required a factor
POSTEnroll a passkey to complete a sign-in that required a factor
Was this page helpful?

Tell us how we can improve this guide.