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

# Authenticator Apps

Authenticator apps provide a time-based one-time password (TOTP) that can be used for authentication.

## Prerequisites

* You need to have the Dynamic Client initialized.
* You need to have the authenticator apps MFA enabled in your environment's settings in the [Dynamic dashboard](https://app.dynamic.xyz/dashboard/security).

## Registering a new TOTP device

Calling `registerTotpMfaDevice` will return a URI and a secret key for the TOTP device.
You can use the URI to display a QR code to the user, so they can scan it with their authenticator app to get a TOTP code.

Unlike passkeys, registering a TOTP device will not automatically authenticate it, so you need to call `authenticateTotpMfaDevice` after registering
a TOTP device for the user to complete an MFA challenge.

```javascript theme={"system"}
import { registerTotpMfaDevice } from '@dynamic-labs-sdk/client';

const register = async () => {
  const { uri, secret } = await registerTotpMfaDevice();
  console.log(uri, secret);
};

```

## Doing MFA authentication with a TOTP code

Calling `authenticateTotpMfaDevice` will verify the TOTP code and complete the MFA challenge.
The authentication will be successful if the user enters a valid TOTP code for the registered TOTP device.

```javascript theme={"system"}
import { authenticateTotpMfaDevice } from '@dynamic-labs-sdk/client';

const onLogin = async () => {
  await authenticateTotpMfaDevice({ code: '123456' });
};
```

### With step-up authentication (recommended)

Pass `requestedScopes` to receive an [elevated access token](/overview/authentication/step-up-auth) for sensitive actions:

```javascript theme={"system"}
import { authenticateTotpMfaDevice } from '@dynamic-labs-sdk/client';

const onExportPrivateKeyClick = async () => {
  await authenticateTotpMfaDevice({
    code: '123456',
    requestedScopes: ['wallet:export'],
  });

  // Elevated token is now stored — the SDK attaches it automatically
  await exportWaasPrivateKey(params);
};
```

### With MFA token (deprecated)

<Warning>
  `createMfaTokenOptions` is deprecated and will be removed in the next major version. Use `requestedScopes` instead. See [migration guide](/overview/authentication/step-up-auth#migration-from-mfa-tokens).
</Warning>

```javascript theme={"system"}
import { authenticateTotpMfaDevice } from '@dynamic-labs-sdk/client';

const onExportPrivateKeyClick = async () => {
  await authenticateTotpMfaDevice({
    code: '123456',
    createMfaTokenOptions: { singleUse: true },
  });

  await exportWaasPrivateKey(params);
};
```

## Deleting a TOTP device

Calling `deleteMfaDevice` will delete a TOTP device associated with the authenticated user.

To delete a TOTP device, you first need to get the user to perfome an authentication challenge with that TOTP device, and then use the `deleteMfaDevice` function with that MFA token.

```javascript theme={"system"}
import { deleteMfaDevice } from '@dynamic-labs-sdk/client';

const delete = async () => {
  // Authenticate with the TOTP device to be deleted
  // Replace '123456' with the actual TOTP code the user enters
  await authenticateTotpMfaDevice({
    code: '123456',
    createMfaTokenOptions: { singleUse: true },
  });

  // Get the MFA token from the dynamic client
  const mfaToken = dynamicClient.mfaToken;

  // Replace 'device-id' with the actual ID of the TOTP device you want to delete
  // Replace 'mfa-auth-token' with the actual MFA authentication token
  await deleteMfaDevice({ deviceId: 'device-id', mfaAuthToken: mfaToken });
};

```

## Getting all registered TOTP devices for a user

Calling `getMfaDevices` will return all registered TOTP devices for the authenticated user.
Currently, only one TOTP device is supported per user.

```javascript theme={"system"}
import { getMfaDevices } from '@dynamic-labs-sdk/client';

const getUserMfaDevices = async () => {
  const mfaDevices = await getMfaDevices();
  console.log(mfaDevices);
};

```

## React

The TOTP flow requires multiple steps: register the device with `useRegisterTotpMfaDevice` (its `data` holds the URI/QR code), then verify with `useAuthenticateTotpMfaDevice`:

```tsx theme={"system"}
import {
  useAuthenticateTotpMfaDevice,
  useRegisterTotpMfaDevice,
} from '@dynamic-labs-sdk/react-hooks';
import { useState } from 'react';

function TotpEnrollment() {
  const [code, setCode] = useState('');

  const { mutate: registerDevice, data: registration } = useRegisterTotpMfaDevice();
  const { mutate: authenticateDevice, isSuccess: enrolled } = useAuthenticateTotpMfaDevice();

  if (enrolled) return <p>TOTP device enrolled successfully.</p>;

  return (
    <div>
      {!registration ? (
        <button onClick={() => registerDevice()}>Set Up Authenticator App</button>
      ) : (
        <form
          onSubmit={(e) => {
            e.preventDefault();
            authenticateDevice({ code });
          }}
        >
          <p>Scan this QR code with your authenticator app:</p>
          {/* render QR code from registration.uri using a QR library */}
          <input
            value={code}
            onChange={(e) => setCode(e.target.value)}
            placeholder="Enter 6-digit code"
            maxLength={6}
          />
          <button type="submit">Verify</button>
        </form>
      )}
    </div>
  );
}
```

## Related functions

* [Step-Up Authentication](/javascript/authentication-methods/step-up-auth/overview)
* [Passkeys](/javascript/authentication-methods/mfa/passkey)
* [Recovery Codes](/javascript/authentication-methods/mfa/recovery-codes)
* [Overview](/javascript/authentication-methods/mfa/overview)
* [Session-Based MFA](/javascript/authentication-methods/mfa/session-mfa)
* [Action-Based MFA](/javascript/authentication-methods/mfa/action-based)
