Example Docs

Two Factor Authentication

Two factor authentication (2FA) adds an extra layer of security by requiring users to provide a second form of verification beyond their password.

Installation

The 2FA plugin is included in the Better Auth package:

import { betterAuth } from "better-auth";
import { twoFactor } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    twoFactor({
      issuer: "MyApp", // Shows in authenticator apps
      backupCodes: {
        enabled: true,
        count: 10, // Number of backup codes
        length: 8, // Length of each code
      },
    }),
  ],
});

Client Setup

import { createAuthClient } from "better-auth/react";
import { twoFactorClient } from "better-auth/client/plugins";

export const authClient = createAuthClient({
  plugins: [twoFactorClient()],
});

Enabling 2FA for a User

Step 1: Generate TOTP Secret

const { data } = await authClient.twoFactor.enable();

// data.totpURI — Use this to generate a QR code
// data.backupCodes — Show these to the user (one time only!)

Step 2: Show QR Code

import QRCode from "qrcode.react";

function Setup2FA({ totpURI }: { totpURI: string }) {
  return (
    <div>
      <h2>Scan this QR code with your authenticator app</h2>
      <QRCode value={totpURI} size={200} />
      <p>Supported apps: Google Authenticator, Authy, 1Password</p>
    </div>
  );
}

Step 3: Verify Initial Code

const { data, error } = await authClient.twoFactor.verifyTotp({
  code: "123456", // Code from authenticator app
});

if (error) {
  console.error("Invalid code");
} else {
  console.log("2FA enabled successfully!");
}

Sign-In with 2FA

When 2FA is enabled, sign-in becomes a two-step process:

// Step 1: Email & Password
const result = await signIn.email({
  email: "user@example.com",
  password: "password123",
});

// If 2FA is enabled, result.twoFactorRequired will be true
if (result.data?.twoFactorRequired) {
  // Step 2: Show TOTP input
  const { data, error } = await authClient.twoFactor.verifyTotp({
    code: userEnteredCode,
  });
}

Backup Codes

Backup codes allow users to sign in if they lose access to their authenticator app:

// Use a backup code instead of TOTP
const { data, error } = await authClient.twoFactor.verifyBackupCode({
  code: "ABCD-1234",
});

Regenerate Backup Codes

const { data } = await authClient.twoFactor.generateBackupCodes();
// data.backupCodes — new set of codes (previous ones are invalidated)

Always remind users to save their backup codes in a secure location. They cannot be retrieved after the initial display.

Disabling 2FA

const { error } = await authClient.twoFactor.disable({
  password: "current-password", // Require password confirmation
});

Configuration Reference

OptionTypeDefaultDescription
issuerstringrequiredName shown in authenticator apps
periodnumber30TOTP code rotation period (seconds)
digitsnumber6Number of digits in TOTP code
algorithmstring"SHA1"Hash algorithm
backupCodes.enabledbooleantrueEnable backup codes
backupCodes.countnumber10Number of backup codes
backupCodes.lengthnumber8Length of each backup code