Skip to main content
Action-Based MFA requires users to verify their identity for sensitive actions like transactions.

Dashboard Setup

  1. Go to the Security page.
  2. In the Action MFA section, enable your desired methods (TOTP and/or Passkeys).
  3. (Optional) Toggle “Require at onboarding” to force MFA setup during signup.
  4. Choose which events you want to protect with MFA and toggle them on.

Your UI SDK Implementation

  • TOTP
  • Passkey
  • Check requirement: Use useIsMfaRequiredForAction() for the specific action.
  • Check token: Use useGetMfaToken() if MFA is required.
  • Create token: If missing, collect OTP and call authenticateDevice({ code, createMfaToken }).
  • Perform action: Token is applied automatically after creation.
import { useMfa, useIsMfaRequiredForAction } from "@dynamic-labs/sdk-react-core";
import { useGetMfaToken } from "@dynamic-labs/sdk-react-core";
import { MFAAction } from '@dynamic-labs/sdk-api-core';

export function EnsureTotpMfaToken() {
    const { authenticateDevice } = useMfa();
    const { getMfaToken } = useGetMfaToken();
    const isMfaRequiredForAction = useIsMfaRequiredForAction();

    const ensureToken = async (code?: string) => {
        const requires = await isMfaRequiredForAction({
            mfaAction: MFAAction.WalletWaasSign,
        });
        if (!requires) {
            // No MFA required for this action
            return;
        }

        const existing = await getMfaToken();
        if (existing) return existing;

        if (!code) throw new Error("OTP code required");
        const token = await authenticateDevice({
            code,
            createMfaToken: { singleUse: true } // or false for persistent
        });
        // Now perform the action that requires Action-Based MFA
        return token;
    };

    return null;
}
  • Only one verified TOTP device per user (device management applies across modes).
  • Recovery codes are single-use; regenerate with getRecoveryCodes(true) if exhausted.
Troubleshooting
  • Error: “MFA required” despite prompting — check useGetMfaToken() and attach token to backend requests.
  • Token unexpectedly missing — persistent tokens expire with session; create a new token when needed.

Dynamic UI Implementation

Note: The Dynamic UI is method-agnostic. It automatically prompts with whichever MFA method(s) you have enabled (TOTP and/or Passkeys). For action-based MFA, check if the specific action requires MFA and then open the Dynamic UI to create an MFA token.
import { usePromptMfaAuth, useIsMfaRequiredForAction } from "@dynamic-labs/sdk-react-core";
import { MFAAction } from '@dynamic-labs/sdk-api-core';

const isMfaRequiredForAction = useIsMfaRequiredForAction();
const promptMfaAuth = usePromptMfaAuth();

// Check if MFA is required for the action
const isMfaRequired = await isMfaRequiredForAction({
  mfaAction: MFAAction.WalletWaasSign, // Specify action configured for Action-Based MFA
});

if (isMfaRequired) {
  // Opens the Dynamic UI to prompt the user to authenticate with MFA
  await promptMfaAuth({ createMfaToken: true }); // Create a single-use token for the action
}
// Perform the action
await primaryWallet.signMessage('Hello, world');
I