---
title: "Verify Login"
method: POST
path: "/auth/mfa/verify-login"
tags: ["Auth"]
---

# Verify Login

`POST /auth/mfa/verify-login`

## Request

- Base URL: `http://localhost:8000`
- URL: `http://localhost:8000/auth/mfa/verify-login`
- Auth: none declared

Exchange the 5-minute ``mfa_challenge_token`` (returned by
/login when the user has active MFA) for a real session JWT.

Three ``method`` values are accepted:

- ``totp``: standard 6-digit code from the authenticator app.
  Issues a full session token (``mfa_satisfied=true,
  mfa_recovery=false``).
- ``webauthn``: ``webauthn_response`` carries the JSON object the
  browser produced from ``navigator.credentials.get`` (after the
  separate ``/login/webauthn/begin`` call). Same outcome as
  ``totp`` on success.
- ``recovery_code``: one of the 8-char ``XXXX-XXXX`` codes
  generated at enrolment. Single-use. Issues a *restricted*
  session (``mfa_satisfied=true, mfa_recovery=true``) — the
  ``get_admin_user`` dependency rejects this token on every
  extranet route, forcing the user through /account/security to
  enrol a fresh method before resuming work.

## Headers

- `API-Version` '1'

## Request body

- MfaVerifyLoginRequest: POST body for /auth/mfa/verify-login. For ``method="totp"`` and ``method="recovery_code"`` the value sits in ``code``. For ``method="webauthn"`` the browser's ``navigator.credentials.get`` response goes in ``webauthn_response`` and ``code`` is empty/ignored — kept on the schema so the discriminator stays open.
  - `mfa_challenge_token` string, required
  - `code` string
  - `method` 'totp' | 'webauthn' | 'recovery_code'
  - `webauthn_response` object, nullable

## Response `200`

Successful Response

- UserPublic
  - `id` integer, required
  - `username` string, email, required
  - `firstname` string, nullable
  - `lastname` string, nullable
  - `displayname` string, nullable
  - `phone` string, nullable
  - `register_date` string, date-time, required
  - `roles` unknown[]
    - unknown
  - `profile_pic` string, required
  - `access_token` string, nullable
  - `pending_email` string, nullable
  - `mfa_satisfied` boolean
  - `mfa_enrolled` boolean
  - `mfa_recovery` boolean
  - `mfa_access_required` boolean

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/totalparks/apis/total-parks-public-api.md) · [All operations](https://skmtc.dev/totalparks/apis/total-parks-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/totalparks/apis/total-parks-public-api/revisions/dcb4c822e2c6?raw)
