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
| Option | Type | Default | Description |
|---|---|---|---|
issuer | string | required | Name shown in authenticator apps |
period | number | 30 | TOTP code rotation period (seconds) |
digits | number | 6 | Number of digits in TOTP code |
algorithm | string | "SHA1" | Hash algorithm |
backupCodes.enabled | boolean | true | Enable backup codes |
backupCodes.count | number | 10 | Number of backup codes |
backupCodes.length | number | 8 | Length of each backup code |