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

# Multi-factor

> Nile Auth React components for MFA setup, challenge, and disable flows

Client-side MFA UI powered by `@niledatabase/react`. These components pair with `useMultiFactor` (and the low-level `mfa` helper) to enroll authenticator or email factors, verify challenges, and disable MFA when needed. The `User` object (obtained via `useSession`) will include a `multiFactor` property if MFA is enabled for the user.

## Authenticator setup

`<MultiFactorAuthenticator />` renders the otpauth QR, recovery codes, and a verification form. Pair it with `useMultiFactor` to start setup and render the payload.

> [tab] Preview
>
> [https://storybook.thenile.dev/iframe.html?globals=\&args=\&id=multifactor-setupauthenticator--default](https://storybook.thenile.dev/iframe.html?globals=\&args=\&id=multifactor-setupauthenticator--default)

> [tab] Component
>
> ```tsx theme={null}
> import { useMultiFactor, MultiFactorAuthenticator } from '@niledatabase/react';
>
> export function AuthenticatorSetupCard() {
>   const { setup, loading, startSetup, errorType } = useMultiFactor({
>     method: 'authenticator',
>     currentMethod: null,
>   });
>
> return (
>
> <div className="space-y-4">
> <button onClick={startSetup} disabled={loading}>
> {loading ? 'Starting...' : 'Enable authenticator MFA'}
> </button>
>
>       {setup?.method === 'authenticator' && setup.scope === 'setup' ? (
>         <MultiFactorAuthenticator
>           setup={setup}
>           onError={(msg) => console.error('MFA error', msg)}
>           onSuccess={(scope) => scope === 'setup' && window.location.reload()}
>         />
>       ) : null}
>
>       {errorType ? <p className="text-red-600">Unable to start MFA ({errorType})</p> : null}
>     </div>
>
> );
> }
>
> ```

## Email setup

`<MultiFactorEmail />` shows masked email messaging and a verification form. Pair it with `useMultiFactor` to start setup and render the payload.

```tsx theme={null}
import { useMultiFactor, MultiFactorEmail } from '@niledatabase/react';

export function EmailSetupCard() {
  const { setup, loading, startSetup, errorType } = useMultiFactor({
    method: 'email',
    currentMethod: null,
  });

  return (
    <div className="space-y-4">
      <button onClick={startSetup} disabled={loading}>
        {loading ? 'Starting...' : 'Enable email MFA'}
      </button>

      {setup?.method === 'email' && setup.scope === 'setup' ? (
        <MultiFactorEmail
          setup={setup}
          onSuccess={(scope) => scope === 'setup' && window.location.reload()}
        />
      ) : null}

      {errorType ? <p className="text-red-600">Unable to start MFA ({errorType})</p> : null}
    </div>
  );
}
```

## Challenge content (sign-in or disable)

`<MultiFactorChallenge />` verifies a code during sign-in, setup verification, or disable flows. Feed it the `setup` payload returned from `useMultiFactor` (or the `/auth/mfa` API) and handle success.

> [tab] Preview
>
> [https://storybook.thenile.dev/iframe.html?globals=\&args=\&id=multifactor-challengecontent--authenticator-challenge](https://storybook.thenile.dev/iframe.html?globals=\&args=\&id=multifactor-challengecontent--authenticator-challenge)

> [tab] Component
>
> ```tsx theme={null}
> import { useMultiFactor, MultiFactorChallenge } from '@niledatabase/react';
>
> export function AuthenticatorChallenge({ existingToken }: { existingToken?: string }) {
>   const { setup, startDisable } = useMultiFactor({
>     method: 'authenticator',
>     currentMethod: 'authenticator',
>   });
>
> // Example: startDisable() would populate `setup` with a challenge payload when confirmation is required.
> return (
>
> <div className="space-y-4">
> <button onClick={startDisable}>Disable MFA</button>
>
>       {setup && setup.scope === 'challenge' ? (
>         <MultiFactorChallenge
>           payload={{ token: setup.token, scope: setup.scope, method: setup.method }}
>           isEnrolled
>           message="Enter a code from your authenticator (or a recovery code)."
>           onSuccess={() => window.location.replace('/app')}
>         />
>       ) : null}
>     </div>
>
> );
> }
>
> ```

## Hooks

### `useMultiFactor(options)`

Manages MFA setup and disable flows and provides the payloads rendered by the components above.

| Name | Type | Default | Description |
| - | - | - | - |
| `method` | `'authenticator' \| 'email'` | *(required)* | MFA mechanism to enable or disable. |
| `currentMethod` | `'authenticator' \| 'email' \| null` | `null` | Currently enrolled method; blocks switching until disabled. |
| `onRedirect` | `(url: string) => void` | `window.location.assign` | Handle `{ url }` redirect responses (`ChallengeRedirect`). |
| `onChallengeRedirect` | `(params: { token; method; scope; destination? }) => void` | Internal `/mfa/prompt` navigation | Override the default challenge redirect builder. |

Returns `{ setup, loading, errorType, startSetup, startDisable }`.

* `setup`: MFA payload for rendering components. Authenticator shape: `{ method: 'authenticator'; token; scope; otpauthUrl?; secret?; recoveryKeys? }`. Email shape: `{ method: 'email'; token; scope; maskedEmail? }`.
* `startSetup()`: begins enrollment (POST `/auth/mfa`); `setup.scope` can be `"setup"` or `"challenge"` when verification is required.
* `startDisable()`: starts removal for the given method. If verification is required, `setup.scope` will be `"challenge"`.
* `errorType`: one of `setup`, `disable`, `parseSetup`, `parseDisable`, or `null`.

### `mfa(options)` (low-level helper)

Wrapper around `/auth/mfa` from `@niledatabase/client`. Use it for custom prompts or headless flows; the React components call this under the hood.

* `POST` `{ method, scope: 'setup' }` → returns a setup payload.
* `PUT` `{ token, code, method, scope }` → verifies a challenge; returns `{ ok: true; scope; recoveryCodesRemaining? }`.
* `DELETE` `{ token?, code?, method, remove: true }` → disables MFA; may require a valid code/token depending on backend settings.
* Redirects surface as `{ url: string }` (`ChallengeRedirect`); parse `error` from the query string for messaging.

**Notes**

* Codes are 6 digits for authenticator/email verification; recovery codes are string tokens issued during setup.
* Tokens expire; expect 410 for stale tokens and 404 for missing challenges.
* Email MFA may require the same token for verification and disable flows.

## Related Components

* [MFA Concepts](https://thenile.dev/docs/auth/concepts/multifactor.md)
* [Sign In](https://thenile.dev/docs/auth/components/signin.md)
* [Sign Out](https://thenile.dev/docs/auth/components/signout.md)
* [User Profile](https://thenile.dev/docs/auth/components/user.md)

```
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.