AnkraDocs
Console

API reference · Access and identity

Two-factor authentication

9 operations of the Ankra Cloud API: Multi-factor authentication: the second sign-in step (a TOTP code or a recovery code), setting up and turning off an authenticator app, recovery codes, and the account owner's requirement of a second factor for every member.

Your second factor and whether the account requires one#

GET/v1/account/mfa
Operation
get_account_mfa
Credentials
Portal session
Requires
Permission self

Session-only; API tokens never see how anyone signs in.

Responses

200Your second factor.application/json · SecondFactorStatus

200 response fields
FieldTypeDescription
totp_enabledrequiredboolean
totp_pendingrequiredbooleanA setup was started and waits for its first code.
enabled_atrequiredstring (date-time) | null
recovery_codes_remainingrequiredinteger
required_by_accountrequiredbooleanThe owner requires a second factor of every member; it cannot be turned off.
availablerequiredbooleanFalse when the control plane has no secret key and cannot seal authenticator secrets.
  • 401Not signed in, or the credential is invalid or expired.
  • 403The role lacks the permission, the token is read-only (a read-only token also gets reason: read_only_token_cannot_read_credentials on every credential read), the CSRF header is missing, a support session may not do this, or the route needs a verified email address and the caller's is not (reason: email_unverified).
  • defaultAny other error, usually 500.

Example

bash
curl 'https://cloud.ankra.app/v1/account/mfa' \
  -b "ankracloud_session=$SESSION"

Require a second factor of every member (owner only)#

PUT/v1/account/mfa/policy
Operation
set_account_mfa_policy
Credentials
Portal session
Requires
Permission members.manage

required: true makes every member without a second factor set one up at their next sign-in; sessions already open keep running until they end. Only the owner may change it, and only with a second factor of their own (409 otherwise). Session-only. Audited as account.mfa_policy_changed.

Request bodyapplication/json

Request body fields
FieldTypeDescription
requiredrequiredboolean

Responses

200The owner's second factor with the new requirement.application/json · SecondFactorStatus

200 response fields
FieldTypeDescription
totp_enabledrequiredboolean
totp_pendingrequiredbooleanA setup was started and waits for its first code.
enabled_atrequiredstring (date-time) | null
recovery_codes_remainingrequiredinteger
required_by_accountrequiredbooleanThe owner requires a second factor of every member; it cannot be turned off.
availablerequiredbooleanFalse when the control plane has no secret key and cannot seal authenticator secrets.
  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 403The role lacks the permission, the token is read-only (a read-only token also gets reason: read_only_token_cannot_read_credentials on every credential read), the CSRF header is missing, a support session may not do this, or the route needs a verified email address and the caller's is not (reason: email_unverified).
  • 409The resource's state does not allow this now.
  • defaultAny other error, usually 500.

Example

bash
curl -X PUT 'https://cloud.ankra.app/v1/account/mfa/policy' \
  -b "ankracloud_session=$SESSION" \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "required": false
}'

Replace your recovery codes#

POST/v1/account/mfa/recovery-codes
Operation
replace_account_recovery_codes
Credentials
Portal session
Requires
Permission self

Needs a current code or a recovery_code. Every earlier recovery code stops working; ten new ones are returned once. Session-only; refused to support sessions. Audited as account.mfa_recovery_codes_regenerated.

Request bodyapplication/json · SecondFactorProof

Request body fields
FieldTypeDescription
codestringSix digits from the authenticator app.
recovery_codestringOne of the single-use recovery codes.

Responses

200The new recovery codes.application/json · RecoveryCodes

200 response fields
FieldTypeDescription
recovery_codesrequiredarray of stringTen single-use codes, shown once.
  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 403The role lacks the permission, the token is read-only (a read-only token also gets reason: read_only_token_cannot_read_credentials on every credential read), the CSRF header is missing, a support session may not do this, or the route needs a verified email address and the caller's is not (reason: email_unverified).
  • 404No such resource in the caller's account.
  • 429Rate limited or the email is locked out.
  • defaultAny other error, usually 500.

Example

bash
curl -X POST 'https://cloud.ankra.app/v1/account/mfa/recovery-codes' \
  -b "ankracloud_session=$SESSION" \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "123456",
  "recovery_code": "string"
}'

Start setting up an authenticator app#

POST/v1/account/mfa/totp
Operation
start_account_totp_setup
Credentials
Portal session
Requires
Permission self

A new TOTP secret (RFC 6238: SHA-1, six digits, 30 seconds), returned once as secret and as the otpauth_uri to render as a QR code; it replaces an earlier unconfirmed one and is not active until POST /v1/account/mfa/totp/confirm. 409 while an authenticator is set up. Session-only; refused to support sessions. Audited as account.mfa_setup_started.

Responses

200The secret, shown once.application/json · AuthenticatorSetup

200 response fields
FieldTypeDescription
secretrequiredstringBase32, for typing into the app.
otpauth_urirequiredstringotpauth://totp/… for the QR code; render it locally.
expires_atrequiredstring (date-time)Confirm with the first code before this.
  • 401Not signed in, or the credential is invalid or expired.
  • 403The role lacks the permission, the token is read-only (a read-only token also gets reason: read_only_token_cannot_read_credentials on every credential read), the CSRF header is missing, a support session may not do this, or the route needs a verified email address and the caller's is not (reason: email_unverified).
  • 409The resource's state does not allow this now.
  • 503No capacity or address is free, or a host did not answer; try again later.
  • defaultAny other error, usually 500.

Example

bash
curl -X POST 'https://cloud.ankra.app/v1/account/mfa/totp' \
  -b "ankracloud_session=$SESSION" \
  -H "X-CSRF-Token: $CSRF_TOKEN"

Turn the authenticator app off#

DELETE/v1/account/mfa/totp
Operation
disable_account_totp
Credentials
Portal session
Requires
Permission self

Needs a current code or a recovery_code. Refused (409) while the account requires a second factor. Session-only; refused to support sessions. Audited as account.mfa_disabled, wrong codes as auth.mfa_failed.

Request bodyapplication/json · SecondFactorProof

Request body fields
FieldTypeDescription
codestringSix digits from the authenticator app.
recovery_codestringOne of the single-use recovery codes.

Responses

204The authenticator and every recovery code are gone.

  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 403The role lacks the permission, the token is read-only (a read-only token also gets reason: read_only_token_cannot_read_credentials on every credential read), the CSRF header is missing, a support session may not do this, or the route needs a verified email address and the caller's is not (reason: email_unverified).
  • 404No such resource in the caller's account.
  • 409The resource's state does not allow this now.
  • 429Rate limited or the email is locked out.
  • defaultAny other error, usually 500.

Example

bash
curl -X DELETE 'https://cloud.ankra.app/v1/account/mfa/totp' \
  -b "ankracloud_session=$SESSION" \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "123456",
  "recovery_code": "string"
}'

Activate the authenticator app with its first code#

POST/v1/account/mfa/totp/confirm
Operation
finish_account_totp_setup
Credentials
Portal session
Requires
Permission self

Returns the ten single-use recovery codes, once; they are stored hashed. Session-only; refused to support sessions. Audited as account.mfa_enabled.

Request bodyapplication/json · AuthenticatorCodeRequest

Request body fields
FieldTypeDescription
coderequiredstringSix digits from the authenticator app.

Responses

200Active; keep the recovery codes.application/json · RecoveryCodes

200 response fields
FieldTypeDescription
recovery_codesrequiredarray of stringTen single-use codes, shown once.
  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 403The role lacks the permission, the token is read-only (a read-only token also gets reason: read_only_token_cannot_read_credentials on every credential read), the CSRF header is missing, a support session may not do this, or the route needs a verified email address and the caller's is not (reason: email_unverified).
  • 409The resource's state does not allow this now.
  • 429Rate limited or the email is locked out.
  • defaultAny other error, usually 500.

Example

bash
curl -X POST 'https://cloud.ankra.app/v1/account/mfa/totp/confirm' \
  -b "ankracloud_session=$SESSION" \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
  "code": "123456"
}'

Finish a sign-in with a code from the authenticator app or a recovery code#

POST/v1/auth/login/mfa
Operation
verify_login_second_factor
Credentials
None (public)

Takes the challenge from the password step (or from the identity provider sign-in, which lands on the portal's /login/mfa page with it in the URL fragment) and exactly one of code (six digits, each accepted once) and recovery_code (single use). Sets the session cookies like POST /v1/auth/login and applies its end_other_sessions. Limited to 10 attempts per client address per minute; repeated wrong codes lock the user's second factor out. Audited as auth.login (and auth.mfa_recovery_code_used), wrong codes as auth.mfa_failed.

Request bodyapplication/json · SecondFactorLoginRequest

Request body fields
FieldTypeDescription
challengerequiredstring
codestringSix digits from the authenticator app.
recovery_codestringOne of the single-use recovery codes (verify only).

Responses

200Signed in.application/json · SecondFactorSession

200 response fields
FieldTypeDescription
userrequiredUser
idrequiredstring
emailrequiredstring
namestringSet for users who signed up themselves.
account_idrequiredstring
rolerequiredstringOne of owner, admin, member, viewer
csrf_tokenrequiredstring
expires_atrequiredstring (date-time)
ended_sessionsintegerSign-in only: how many other sessions end_other_sessions ended.
recovery_codesarray of stringAfter a setup at sign-in: the ten recovery codes, shown once.
recovery_codes_remainingintegerAfter a code check: how many unused recovery codes are left.
return_tostringAfter an identity provider sign-in: where the portal continues.
  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 409The resource's state does not allow this now.
  • 429Rate limited or the email is locked out.
  • 503No capacity or address is free, or a host did not answer; try again later.
  • defaultAny other error, usually 500.

Example

bash
curl -X POST 'https://cloud.ankra.app/v1/auth/login/mfa' \
  -H 'Content-Type: application/json' \
  -d '{
  "challenge": "string"
}'

Start setting up the authenticator app the account requires, before the first session#

POST/v1/auth/login/mfa/enroll
Operation
start_login_second_factor_setup
Credentials
None (public)

With an enroll challenge: a new TOTP secret for the user, returned once as secret and as the otpauth_uri the portal renders as a QR code. It is not active until .../enroll/confirm receives its first code.

Request bodyapplication/json · SecondFactorChallengeRequest

Request body fields
FieldTypeDescription
challengerequiredstring

Responses

200The secret, shown once.application/json · AuthenticatorSetup

200 response fields
FieldTypeDescription
secretrequiredstringBase32, for typing into the app.
otpauth_urirequiredstringotpauth://totp/… for the QR code; render it locally.
expires_atrequiredstring (date-time)Confirm with the first code before this.
  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 409The resource's state does not allow this now.
  • 429Rate limited or the email is locked out.
  • 503No capacity or address is free, or a host did not answer; try again later.
  • defaultAny other error, usually 500.

Example

bash
curl -X POST 'https://cloud.ankra.app/v1/auth/login/mfa/enroll' \
  -H 'Content-Type: application/json' \
  -d '{
  "challenge": "string"
}'

Activate the new authenticator with its first code and sign in#

POST/v1/auth/login/mfa/enroll/confirm
Operation
finish_login_second_factor_setup
Credentials
None (public)

The first code activates the authenticator; the ten recovery codes are returned once, and the session cookies are set. Audited as account.mfa_enabled and auth.login.

Request bodyapplication/json · SecondFactorLoginRequest

Request body fields
FieldTypeDescription
challengerequiredstring
codestringSix digits from the authenticator app.
recovery_codestringOne of the single-use recovery codes (verify only).

Responses

200Signed in; keep the recovery codes.application/json · SecondFactorSession

200 response fields
FieldTypeDescription
userrequiredUser
idrequiredstring
emailrequiredstring
namestringSet for users who signed up themselves.
account_idrequiredstring
rolerequiredstringOne of owner, admin, member, viewer
csrf_tokenrequiredstring
expires_atrequiredstring (date-time)
ended_sessionsintegerSign-in only: how many other sessions end_other_sessions ended.
recovery_codesarray of stringAfter a setup at sign-in: the ten recovery codes, shown once.
recovery_codes_remainingintegerAfter a code check: how many unused recovery codes are left.
return_tostringAfter an identity provider sign-in: where the portal continues.
  • 400The request is invalid; detail says why.
  • 401Not signed in, or the credential is invalid or expired.
  • 409The resource's state does not allow this now.
  • 429Rate limited or the email is locked out.
  • 503No capacity or address is free, or a host did not answer; try again later.
  • defaultAny other error, usually 500.

Example

bash
curl -X POST 'https://cloud.ankra.app/v1/auth/login/mfa/enroll/confirm' \
  -H 'Content-Type: application/json' \
  -d '{
  "challenge": "string"
}'