> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spitshake.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Factor Authentication

> Set up and enforce TOTP-based multi-factor authentication for your DocuTrust account.

# Multi-Factor Authentication (MFA)

DocuTrust supports Time-Based One-Time Password (TOTP) MFA, compatible with any authenticator app that implements the TOTP standard (RFC 6238), including Google Authenticator, Authy, 1Password, and Microsoft Authenticator.

## Setup Flow

### Step 1: Initiate MFA Setup

Request a new TOTP secret and QR code for the authenticated user.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://your-app.com/api/mfa/setup \
    -H "X-Auth-Token: YOUR_API_TOKEN" \
    -H "Content-Type: application/json"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://your-app.com/api/mfa/setup", {
    method: "POST",
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN",
      "Content-Type": "application/json"
    }
  });
  const data = await response.json();
  ```
</CodeGroup>

**Response** `200 OK`

```json theme={null}
{
  "secret": "JBSWY3DPEHPK3PXP",
  "qr_svg": "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 33 33'><path d='M1,1h1v1h-1z M2,1h1v1h-1z ...' fill='#000000'/></svg>",
  "provisioning_uri": "otpauth://totp/DocuTrust:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=DocuTrust"
}
```

| Field              | Type   | Description                                                                                                            |
| ------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------- |
| `secret`           | string | The TOTP secret key. Users can enter this manually into their authenticator app if they cannot scan the QR code.       |
| `qr_svg`           | string | An SVG image of the QR code that encodes the provisioning URI. Render this in your UI for users to scan.               |
| `provisioning_uri` | string | The `otpauth://` URI following the Google Authenticator Key URI format. Contains the secret, issuer, and account name. |

Display the `qr_svg` to your user so they can scan it with their authenticator app. Alternatively, provide the `secret` for manual entry.

### Step 2: Confirm MFA Setup

After the user scans the QR code and generates their first code, confirm the setup by submitting the 6-digit code.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://your-app.com/api/mfa/confirm \
    -H "X-Auth-Token: YOUR_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "code": "482916"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://your-app.com/api/mfa/confirm", {
    method: "POST",
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      code: "482916"
    })
  });
  const data = await response.json();
  ```
</CodeGroup>

**Request Body**

| Field  | Type   | Required | Description                                       |
| ------ | ------ | -------- | ------------------------------------------------- |
| `code` | string | Yes      | The 6-digit TOTP code from the authenticator app. |

**Response** `200 OK`

```json theme={null}
{
  "enabled": true,
  "backup_codes": [
    "abc12345",
    "def67890",
    "ghi13579",
    "jkl24680",
    "mno35791",
    "pqr46802",
    "stu57913",
    "vwx68024"
  ]
}
```

| Field          | Type             | Description                                                                                                                            |
| -------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`      | boolean          | Whether MFA is now active on the account. Always `true` on successful confirmation.                                                    |
| `backup_codes` | array of strings | Eight single-use backup codes. Each code can be used once in place of a TOTP code if the user loses access to their authenticator app. |

<Warning>
  Store backup codes securely. They are only shown once at setup time and cannot be retrieved later. Each code can be used exactly once.
</Warning>

### Step 3: Check MFA Status

Query the current MFA status for the authenticated user.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://your-app.com/api/mfa/status \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://your-app.com/api/mfa/status", {
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN"
    }
  });
  const data = await response.json();
  ```
</CodeGroup>

**Response** `200 OK`

```json theme={null}
{
  "enabled": true,
  "backup_codes_remaining": 8
}
```

| Field                    | Type    | Description                                                                                              |
| ------------------------ | ------- | -------------------------------------------------------------------------------------------------------- |
| `enabled`                | boolean | Whether MFA is currently active for this user.                                                           |
| `backup_codes_remaining` | integer | The number of unused backup codes remaining. Starts at 8 and decrements each time a backup code is used. |

### Step 4: Disable MFA

Disable MFA by providing a valid TOTP code from the authenticator app.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://your-app.com/api/mfa \
    -H "X-Auth-Token: YOUR_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "code": "739201"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://your-app.com/api/mfa", {
    method: "DELETE",
    headers: {
      "X-Auth-Token": "YOUR_API_TOKEN",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      code: "739201"
    })
  });
  ```
</CodeGroup>

**Request Body**

| Field  | Type   | Required | Description                                           |
| ------ | ------ | -------- | ----------------------------------------------------- |
| `code` | string | Yes      | A valid 6-digit TOTP code from the authenticator app. |

**Response** `200 OK`

```json theme={null}
{
  "enabled": false
}
```

<Note>
  If account-level MFA enforcement is active (`mfa_enforced` setting), individual users cannot disable MFA. The request will return `403 Forbidden`.
</Note>

## Login Flow with MFA

When MFA is enabled, the login flow becomes a two-step process:

1. **Password authentication**: The user submits their email and password to `POST /login`. If the credentials are valid and MFA is enabled, the response returns a `302` redirect to `/mfa/verify` instead of completing the login.

2. **TOTP verification**: The user is presented with a form to enter their 6-digit TOTP code (or a backup code). Upon successful verification, the session is created and the user is redirected to the dashboard.

```
POST /login
  email: "user@example.com"
  password: "SecureP@ssw0rd!"

  --> 302 Redirect to /mfa/verify (MFA required)

POST /mfa/verify
  code: "482916"

  --> 302 Redirect to /dashboard (login complete)
```

## Account-Level MFA Enforcement

Administrators can enforce MFA for all users in the account by enabling the `mfa_enforced` setting in **Settings > Security**.

When MFA enforcement is active:

* Users who have not set up MFA are redirected to the MFA setup page on login and cannot access any other admin pages until MFA is configured.
* Users cannot disable their own MFA (the disable endpoint returns `403 Forbidden`).
* New users must configure MFA as part of their first login.

## Backup Codes

Each user receives **8 backup codes** when MFA is first enabled. Backup codes are:

* **Single-use**: Each code can only be used once.
* **Shown once**: Codes are only displayed at MFA setup time. They cannot be retrieved later.
* **Equivalent to TOTP codes**: A backup code can be entered anywhere a TOTP code is requested (login, disable MFA, etc.).
* **Tracked**: The `backup_codes_remaining` field on the status endpoint shows how many unused codes remain.

If a user runs out of backup codes and loses access to their authenticator app, an administrator must disable MFA for that user from the admin panel.

## Error Responses

| Status                     | Error                         | Description                                                                      |
| -------------------------- | ----------------------------- | -------------------------------------------------------------------------------- |
| `400 Bad Request`          | `"Invalid code"`              | The provided TOTP or backup code is incorrect or expired.                        |
| `403 Forbidden`            | `"MFA enforcement is active"` | Cannot disable MFA while account-level enforcement is enabled.                   |
| `409 Conflict`             | `"MFA already enabled"`       | Attempted to set up MFA when it is already active. Call `DELETE /api/mfa` first. |
| `422 Unprocessable Entity` | `"Setup not initiated"`       | Attempted to confirm MFA without first calling `POST /api/mfa/setup`.            |
