two-factor-authentication-best-practices
Better AuthのtwoFactorプラグインを活用し、TOTPアプリやメール/SMSでのOTP送信、バックアップコード管理、信頼済みデバイス処理など、多要素認証(MFA)の安全な設定とログインフローを実装するSkill。
📜 元の英語説明(参考)
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.
🇯🇵 日本人クリエイター向け解説
Better AuthのtwoFactorプラグインを活用し、TOTPアプリやメール/SMSでのOTP送信、バックアップコード管理、信頼済みデバイス処理など、多要素認証(MFA)の安全な設定とログインフローを実装するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o two-factor-authentication-best-practices.zip https://jpskill.com/download/23573.zip && unzip -o two-factor-authentication-best-practices.zip && rm two-factor-authentication-best-practices.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/23573.zip -OutFile "$d\two-factor-authentication-best-practices.zip"; Expand-Archive "$d\two-factor-authentication-best-practices.zip" -DestinationPath $d -Force; ri "$d\two-factor-authentication-best-practices.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
two-factor-authentication-best-practices.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
two-factor-authentication-best-practicesフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
セットアップ
issuerを指定してtwoFactor()プラグインをサーバー設定に追加します。twoFactorClient()プラグインをクライアント設定に追加します。npx @better-auth/cli migrateを実行します。- 検証: ユーザーテーブルに
twoFactorSecretカラムが存在することを確認します。
import { betterAuth } from "better-auth";
import { twoFactor } from "better-auth/plugins";
export const auth = betterAuth({
appName: "My App",
plugins: [
twoFactor({
issuer: "My App",
}),
],
});
クライアントサイドのセットアップ
import { createAuthClient } from "better-auth/client";
import { twoFactorClient } from "better-auth/client/plugins";
export const authClient = createAuthClient({
plugins: [
twoFactorClient({
onTwoFactorRedirect() {
window.location.href = "/2fa";
},
}),
],
});
ユーザーの2FAを有効にする
パスワード認証が必要です。TOTP URI(QRコード用)とバックアップコードを返します。
const enable2FA = async (password: string) => {
const { data, error } = await authClient.twoFactor.enable({
password,
});
if (data) {
// data.totpURI — これからQRコードを生成します
// data.backupCodes — ユーザーに表示します
}
};
twoFactorEnabled は、最初のTOTP検証が成功するまで true に設定されません。skipVerificationOnEnable: true で上書きできます(非推奨)。
TOTP(認証アプリ)
QRコードの表示
import QRCode from "react-qr-code";
const TotpSetup = ({ totpURI }: { totpURI: string }) => {
return <QRCode value={totpURI} />;
};
TOTPコードの検証
現在時刻の1期間前/後のコードを受け入れます。
const verifyTotp = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyTotp({
code,
trustDevice: true,
});
};
TOTP設定オプション
twoFactor({
totpOptions: {
digits: 6, // 6桁または8桁 (デフォルト: 6)
period: 30, // コードの有効期間(秒単位) (デフォルト: 30)
},
});
OTP(メール/SMS)
OTP配信の設定
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, // コードの有効期間(分単位) (デフォルト: 3)
digits: 6, // 桁数 (デフォルト: 6)
allowedAttempts: 5, // 最大検証試行回数 (デフォルト: 5)
},
}),
],
});
OTPの送信と検証
送信: authClient.twoFactor.sendOtp()。検証: authClient.twoFactor.verifyOtp({ code, trustDevice: true })。
OTPストレージのセキュリティ
データベースでのOTPコードの保存方法を設定します。
twoFactor({
otpOptions: {
storeOTP: "encrypted", // オプション: "plain", "encrypted", "hashed"
},
});
カスタム暗号化の場合:
twoFactor({
otpOptions: {
storeOTP: {
encrypt: async (token) => myEncrypt(token),
decrypt: async (token) => myDecrypt(token),
},
},
});
バックアップコード
2FAが有効になると自動的に生成されます。各コードは1回限り使用できます。
バックアップコードの表示
const BackupCodes = ({ codes }: { codes: string[] }) => {
return (
<div>
<p>これらのコードを安全な場所に保存してください:</p>
<ul>
{codes.map((code, i) => (
<li key={i}>{code}</li>
))}
</ul>
</div>
);
};
バックアップコードの再生成
以前のすべてのコードを無効にします。
const regenerateBackupCodes = async (password: string) => {
const { data, error } = await authClient.twoFactor.generateBackupCodes({
password,
});
// data.backupCodes に新しいコードが含まれています
};
リカバリのためのバックアップコードの使用
const verifyBackupCode = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyBackupCode({
code,
trustDevice: true,
});
};
バックアップコードの設定
twoFactor({
backupCodeOptions: {
amount: 10, // 生成するコードの数 (デフォルト: 10)
length: 10, // 各コードの長さ (デフォルト: 10)
storeBackupCodes: "encrypted", // オプション: "plain", "encrypted"
},
});
サインイン時の2FAの処理
2FAが必要な場合、レスポンスには twoFactorRedirect: true が含まれます。
サインインフロー
signIn.email({ email, password })を呼び出します。onSuccessでcontext.data.twoFactorRedirectを確認します。trueの場合、/2fa検証ページにリダイレクトします。- TOTP、OTP、またはバックアップコードで検証します。
- 検証が成功するとセッションクッキーが作成されます。
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";
}
},
}
);
};
サーバーサイド: auth.api.signInEmail を使用する場合、"twoFactorRedirect" in response を確認します。
信頼できるデバイス
検証時に trustDevice: true を渡します。デフォルトの信頼期間は30日 (trustDeviceMaxAge) です。サインインごとに更新されます。
セキュリティに関する考慮事項
セッション管理
フロー: 認証情報 → セッション削除 → 一時的な2FAクッキー(デフォルト10分) → 検証 → セッション作成。
twoFactor({
twoFactorCookieMaxAge: 600, // 10分(秒単位) (デフォルト)
});
レート制限
組み込み: すべての2FAエンドポイントに対して10秒あたり3リクエスト。OTPには追加の試行制限があります。
twoFactor({
otpOptions: {
allowedAttempts: 5, // OTPコードあたりの最大試行回数 (デフォルト: 5)
},
});
保存時の暗号化
TOTPシークレット: 認証シークレットで暗号化されます。バックアップコード: デフォルトで暗号化されます。OTP: 設定可能("plain", "encrypted", "hashed")。検証には定数時間比較を使用します。
2FAは、認証情報(メール/パスワード)アカウントに対してのみ有効にできます。
2FAの無効化
パスワードが必要です。
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Setup
- Add
twoFactor()plugin to server config withissuer - Add
twoFactorClient()plugin to client config - Run
npx @better-auth/cli migrate - Verify: check that
twoFactorSecretcolumn 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
- Call
signIn.email({ email, password }) - Check
context.data.twoFactorRedirectinonSuccess - If
true, redirect to/2faverification page - Verify via TOTP, OTP, or backup code
- 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
}),
],
});