Skip to main content
MFA enrollment is a one-time setup process where users add an authenticator app or phone number to their account. Users can enroll in both methods for backup.

Choose your approach

@coinbase/cdp-react provides ready-to-use components with a polished UI.
Pre-built components support TOTP (authenticator apps). For SMS enrollment, use React hooks below.
import { EnrollMfaModal } from "@coinbase/cdp-react";

function App() {
  return (
    <EnrollMfaModal onEnrollSuccess={() => console.log("Enrolled!")}>
      <button>Set up MFA</button>
    </EnrollMfaModal>
  );
}
For controlled modals, custom layouts, or embedding enrollment in non-modal containers, see the EnrollMfa component reference.

Custom UIs using React Hooks

For custom UI or SMS enrollment, use hooks from @coinbase/cdp-hooks. Enrollment is a two-step process:
  1. Initiate — Call useInitiateMfaEnrollment to start enrollment (returns QR code for TOTP, sends SMS for text message)
  2. Submit — Call useSubmitMfaEnrollment with the 6-digit code to complete enrollment
import { useState } from "react";
import { useInitiateMfaEnrollment, useSubmitMfaEnrollment } from "@coinbase/cdp-hooks";

function TotpEnrollment() {
  const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);
  const { initiateMfaEnrollment } = useInitiateMfaEnrollment();
  const { submitMfaEnrollment } = useSubmitMfaEnrollment();

  async function startEnrollment() {
    // Step 1: Initiate — returns QR code data
    const result = await initiateMfaEnrollment({ mfaMethod: "totp" });
    setQrCodeUrl(result.authUrl); // Display as QR code
    // result.secret → manual entry fallback
  }

  async function completeEnrollment(code: string) {
    // Step 2: Submit — user enters code from authenticator app
    await submitMfaEnrollment({ mfaMethod: "totp", mfaCode: code });
  }

  // Render: QR code from qrCodeUrl, input for code, submit button
}
For complete UI implementations with error handling, loading states, and form validation, see the MFA section in the cdp-hooks reference.

Direct API calls for non-React

For non-React applications, use functions from @coinbase/cdp-core.
import { initiateMfaEnrollment, submitMfaEnrollment } from "@coinbase/cdp-core";

// Step 1: Initiate — returns QR code data
const enrollment = await initiateMfaEnrollment({ mfaMethod: "totp" });
// enrollment.authUrl → use with any QR code library
// enrollment.secret → manual entry fallback

// Step 2: Submit — user enters code from authenticator app
await submitMfaEnrollment({ mfaMethod: "totp", mfaCode: "123456" });
For full API details, see the cdp-core reference.

Checking enrollment status

Before prompting users to enroll, check if they already have MFA enabled.
import { useCurrentUser } from "@coinbase/cdp-hooks";
import { getEnrolledMfaMethods, isEnrolledInMfa } from "@coinbase/cdp-core";

function MyComponent() {
  const { currentUser } = useCurrentUser();

  if (!currentUser) return null;

  const hasMfa = isEnrolledInMfa(currentUser);
  const methods = getEnrolledMfaMethods(currentUser);
  // methods: ['totp'], ['sms'], ['totp', 'sms'], or []

  // Use hasMfa and methods to drive your UI
}

Validating phone numbers

For SMS enrollment, validate phone numbers before submission:
import { validatePhoneNumber } from "@coinbase/cdp-core";

try {
  validatePhoneNumber("+14155552671"); // Valid
  validatePhoneNumber("+442071838750"); // Valid (UK)
  validatePhoneNumber("4155552671");    // Throws - missing +
} catch (error) {
  console.error(error.message);
}
  • Must start with + followed by country code
  • No spaces, hyphens, or parentheses
  • Examples: +14155552671 (US), +442071838750 (UK), +81312345678 (Japan)

Troubleshooting

Common causes:
  • Time synchronization issues between device and server
  • User entering an expired code (TOTP codes refresh every 30 seconds)
  • Incorrect authenticator app setup
Solutions:
  • Ensure device time is synchronized with network time
  • Ask users to wait for a new code and try again
  • Provide option to re-enroll in MFA
  • Verify the QR code was scanned correctly during enrollment
Common causes:
  • Invalid phone number format (not E.164)
  • Carrier delays or filtering
  • Phone number not capable of receiving SMS
  • Rate limiting exceeded
Solutions:
  • Validate phone number format before submission using validatePhoneNumber()
  • Provide clear error messages for rate limiting
  • Offer TOTP as alternative method
  • Allow users to check and update their phone number
Error message: Invalid phone number format. Phone number must be in E.164 format (e.g., +14155552671)Solutions:
  • Use E.164 format: +[country code][subscriber number]
  • Examples:
    • US: +14155552671
    • UK: +442071838750
    • Japan: +81312345678
  • Remove any spaces, hyphens, or parentheses
  • Must start with + and country code (never 0)
  • Use validatePhoneNumber() helper to validate before submission
Recovery options:
  • If user has both TOTP and SMS enrolled, they can use the other method
  • Implement account recovery through primary authentication method
  • Allow MFA reset after verifying via email or other auth method
  • Provide customer support flow for account recovery
  • Consider implementing backup codes for recovery (future enhancement)