本文へ移動
cccskills
無料GitHub で公開

two-factor-authentication-best-practices

Configure TOTP authenticator apps, send OTP codes via email/SMS, manage backup codes, handle trusted devices, and implement 2FA sign-in flows using Better Auth's twoFactor plugin. Use when users need MFA, multi-factor authentication, authenticator setup, or login security with Better Auth.

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-worksスター 182(GitHub 182 + cccskills 0)

実行スコア 未検証

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Setup

  1. Add twoFactor() plugin to server config with issuer
  2. Add twoFactorClient() plugin to client config
  3. Run npx @better-auth/cli migrate
  4. Verify: check that twoFactorSecret column exists on user table
import { betterAuth } from 'better-auth';
import { twoFactor } from 'better-auth/plugins';

export const auth = betterAuth({
	appName: 'My App',
	plugins: [
		twoFactor({
			issuer: 'My App'
		})
	]
});

Client-Side Setup

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

export const authClient = createAuthClient({
	plugins: [
		twoFactorClient({
			onTwoFactorRedirect() {
				window.location.href = '/2fa';
			}
		})
	]
});

Enabling 2FA for Users

Requires password verification. Returns TOTP URI (for QR code) and backup codes.

const enable2FA = async (password: string) => {
	const { data, error } = await authClient.twoFactor.enable({
		password
	});

	if (data) {
		// data.totpURI — generate a QR code from this
		// data.backupCodes — display to user
	}
};

twoFactorEnabled is not set to true until first TOTP verification succeeds. Override with skipVerificationOnEnable: true (not recommended).

TOTP (Authenticator App)

Displaying the QR Code

import QRCode from 'react-qr-code';

const TotpSetup = ({ totpURI }: { totpURI: string }) => {
	return <QRCode value={totpURI} />;
};

Verifying TOTP Codes

Accepts codes from one period before/after current time:

const verifyTotp = async (code: string) => {
	const { data, error } = await authClient.twoFactor.verifyTotp({
		code,
		trustDevice: true
	});
};

TOTP Configuration Options

twoFactor({
	totpOptions: {
		digits: 6, // 6 or 8 digits (default: 6)
		period: 30 // Code validity period in seconds (default: 30)
	}
});

OTP (Email/SMS)

Configuring OTP Delivery

import { betterAuth } from 'better-auth';
import { twoFactor } from 'better-auth/plugins';
import { sendEmail } from './email';

export const auth = betterAuth({
	plugins: [
		twoFactor({
			otpOptions: {
				sendOTP: async ({ user, otp }, ctx) => {
					await sendEmail({
						to: user.email,
						subject: 'Your verification code',
						text: `Your code is: ${otp}`
					});
				},
				period: 5, // Code validity in minutes (default: 3)
				digits: 6, // Number of digits (default: 6)
				allowedAttempts: 5 // Max verification attempts (default: 5)
			}
		})
	]
});

Sending and Verifying OTP

Send: authClient.twoFactor.sendOtp(). Verify: authClient.twoFactor.verifyOtp({ code, trustDevice: true }).

OTP Storage Security

Configure how OTP codes are stored in the database:

twoFactor({
	otpOptions: {
		storeOTP: 'encrypted' // Options: "plain", "encrypted", "hashed"
	}
});

For custom encryption:

twoFactor({
	otpOptions: {
		storeOTP: {
			encrypt: async (token) => myEncrypt(token),
			decrypt: async (token) => myDecrypt(token)
		}
	}
});

Backup Codes

Generated automatically when 2FA is enabled. Each code is single-use.

Displaying Backup Codes

const BackupCodes = ({ codes }: { codes: string[] }) => {
	return (
		<div>
			<p>Save these codes in a secure location:</p>
			<ul>
				{codes.map((code, i) => (
					<li key={i}>{code}</li>
				))}
			</ul>
		</div>
	);
};

Regenerating Backup Codes

Invalidates all previous codes:

const regenerateBackupCodes = async (password: string) => {
	const { data, error } = await authClient.twoFactor.generateBackupCodes({
		password
	});
	// data.backupCodes contains the new codes
};

Using Backup Codes for Recovery

const verifyBackupCode = async (code: string) => {
	const { data, error } = await authClient.twoFactor.verifyBackupCode({
		code,
		trustDevice: true
	});
};

Backup Code Configuration

twoFactor({
	backupCodeOptions: {
		amount: 10, // Number of codes to generate (default: 10)
		length: 10, // Length of each code (default: 10)
		storeBackupCodes: 'encrypted' // Options: "plain", "encrypted"
	}
});

Handling 2FA During Sign-In

Response includes twoFactorRedirect: true when 2FA is required:

Sign-In Flow

  1. Call signIn.email({ email, password })
  2. Check context.data.twoFactorRedirect in onSuccess
  3. If true, redirect to /2fa verification page
  4. Verify via TOTP, OTP, or backup code
  5. Session cookie is created on successful verification
const signIn = async (email: string, password: string) => {
	const { data, error } = await authClient.signIn.email(
		{ email, password },
		{
			onSuccess(context) {
				if (context.data.twoFactorRedirect) {
					window.location.href = '/2fa';
				}
			}
		}
	);
};

Server-side: check "twoFactorRedirect" in response when using auth.api.signInEmail.

Trusted Devices

Pass trustDevice: true when verifying. Default trust duration: 30 days (trustDeviceMaxAge). Refreshes on each sign-in.

Security Considerations

Session Management

Flow: credentials → session removed → temporary 2FA cookie (10 min default) → verify → session created.

twoFactor({
	twoFactorCookieMaxAge: 600 // 10 minutes in seconds (default)
});

Rate Limiting

Built-in: 3 requests per 10 seconds for all 2FA endpoints. OTP has additional attempt limiting:

twoFactor({
	otpOptions: {
		allowedAttempts: 5 // Max attempts per OTP code (default: 5)
	}
});

Encryption at Rest

TOTP secrets: encrypted with auth secret. Backup codes: encrypted by default. OTP: configurable ("plain", "encrypted", "hashed"). Uses constant-time comparison for verification.

2FA can only be enabled for credential (email/password) accounts.

Disabling 2FA

Requires password confirmation. Revokes trusted device records:

const disable2FA = async (password: string) => {
	const { data, error } = await authClient.twoFactor.disable({
		password
	});
};

Complete Configuration Example

import { betterAuth } from 'better-auth';
import { twoFactor } from 'better-auth/plugins';
import { sendEmail } from './email';

export const auth = betterAuth({
	appName: 'My App',
	plugins: [
		twoFactor({
			// TOTP settings
			issuer: 'My App',
			totpOptions: {
				digits: 6,
				period: 30
			},
			// OTP settings
			otpOptions: {
				sendOTP: async ({ user, otp }) => {
					await sendEmail({
						to: user.email,
						subject: 'Your verification code',
						text: `Your code is: ${otp}`
					});
				},
				period: 5,
				allowedAttempts: 5,
				storeOTP: 'encrypted'
			},
			// Backup code settings
			backupCodeOptions: {
				amount: 10,
				length: 10,
				storeBackupCodes: 'encrypted'
			},
			// Session settings
			twoFactorCookieMaxAge: 600, // 10 minutes
			trustDeviceMaxAge: 30 * 24 * 60 * 60 // 30 days
		})
	]
});

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

Audit and improve web accessibility following WCAG 2.2 guidelines. Use when asked to "improve accessibility", "a11y audit", "WCAG compliance", "screen reader support", "keyboard navigation", or "make accessible".

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-works1822026年10月24日 更新

ai-sdk

無料

Answer questions about the AI SDK and help build AI-powered features. Use when developers: (1) Ask about AI SDK functions like generateText, streamText, ToolLoopAgent, embed, or tools, (2) Want to build AI agents, chatbots, RAG systems, or text generation features, (3) Have questions about AI providers (OpenAI, Anthropic, Google, etc.), streaming, tool calling, structured output, or embeddings, (4) Use React hooks like useChat or useCompletion. Triggers on: "AI SDK", "Vercel AI SDK", "generateText", "streamText", "add AI to my app", "build an agent", "tool calling", "structured output", "useChat".

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-works1822026年10月24日 更新

Configure Better Auth server and client, set up database adapters, manage sessions, add plugins, and handle environment variables. Use when users mention Better Auth, betterauth, auth.ts, or need to set up TypeScript authentication with email/password, OAuth, or plugin configuration.

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-works1822026年10月24日 更新

Deploy applications and websites to Vercel. Use when the user requests deployment actions like "deploy my app", "deploy and give me the link", "push this live", or "create a preview deployment".

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-works1822026年10月24日 更新

Configure email verification, implement password reset flows, set password policies, and customise hashing algorithms for Better Auth email/password authentication. Use when users need to set up login, sign-in, sign-up, credential authentication, or password security with Better Auth.

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-works1822026年10月24日 更新

Repo-specific guide to the Ever Works monorepo (ever-works/ever-works) — its pnpm + Turborepo layout, the per-workspace test runners (Jest vs Vitest vs Playwright), file-naming and import-alias conventions, the commit/branch model, and the real build/lint/type-check commands. Use this whenever working anywhere in this repository so changes match the codebase's actual conventions and pass CI.

日本語の概要は準備中です。原文の説明を表示しています。

ever-works/ever-works1822026年10月24日 更新

ever-works のスキルをすべて見る

このスキルの問題を報告する