Two-Factor Authentication adds an extra security layer. Users need both their password AND a code from their phone or email to login.
Perfect for: High-security applications, protecting sensitive data, and meeting compliance requirements.
# Enable 2FA feature
NEXT_PUBLIC_BETTER_AUTH_2FA_ENABLE=true
# Optional: Skip email verification when enabling 2FA
NEXT_PUBLIC_BETTER_AUTH_2FA_SKIP_VERIFICATION_ON_ENABLE=true
# Required for email codes
RESEND_API_KEY="re_your_resend_api_key"
EMAIL_FROM="noreply@yourdomain.com"2FA options automatically appear in user account settings at /[locale]/account/settings.

Authenticator Apps:
How it works:
User visits /[locale]/account/settings and finds the "Two-Factor Authentication" section.
Click "Enable TOTP" button to start the setup process.


User enters the 6-digit code from their app to confirm setup.
System generates recovery codes that user must save safely.

Important: Recovery codes are generated when enabling 2FA. Users must save them securely - they're the only way to recover access if the authenticator app is lost.
Recovery codes features:
User starts with normal login at /[locale]/login.
After successful password, user is redirected to /[locale]/verify-request/totp.
User enters 6-digit code from their authenticator app or email.
After valid code, user is logged in and redirected to dashboard.
If user loses access to their authenticator app:
On the 2FA verification page, click "Use recovery code instead".
User enters one of their saved backup codes.
User is logged in and should immediately set up 2FA again.
Location: /[locale]/account/settings
Available options:
2FA Management Interface:
The boilerplate includes dedicated verification pages:
/[locale]/verify-request/totp - Enter authenticator code/[locale]/verify-request/otp - Enter email code/[locale]/verify-request/recovery - Enter recovery codeThe 2FA feature uses Better Auth's twoFactor plugin:
// In src/lib/better-auth/auth.ts
twoFactor({
issuer: APP_ISSUER,
skipVerificationOnEnable: AuthAppConfig.skipVerificationOnEnable,
totpOptions: {},
otpOptions: {
period: 300, // 5 minutes expiration
sendOTP: async ({user, otp}) => {
const otpLink = `${env.NEXT_PUBLIC_APP_URL}/verify-request/otp?code=${otp}`
await createTypedNotificationService({
userId: user.id,
type: NotificationTypeConst.otp_code,
metadata: { otp, otpLink }
})
}
}
})Built-in security features:
User recommendations:
"Invalid code" errors?
Lost authenticator app?
Email codes not arriving?
RESEND_API_KEY is configured/[locale]/account/settingsAll working? Your users now have military-grade security with easy-to-use two-factor authentication!