jpskill.com
💬 コミュニケーション コミュニティ

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本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
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
🪟 Windows (PowerShell)
$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. 1. 下の青いボタンを押して two-factor-authentication-best-practices.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → two-factor-authentication-best-practices フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

セットアップ

  1. issuer を指定して twoFactor() プラグインをサーバー設定に追加します。
  2. twoFactorClient() プラグインをクライアント設定に追加します。
  3. npx @better-auth/cli migrate を実行します。
  4. 検証: ユーザーテーブルに 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 が含まれます。

サインインフロー

  1. signIn.email({ email, password }) を呼び出します。
  2. onSuccesscontext.data.twoFactorRedirect を確認します。
  3. true の場合、/2fa 検証ページにリダイレクトします。
  4. TOTP、OTP、またはバックアップコードで検証します。
  5. 検証が成功するとセッションクッキーが作成されます。
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

  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
    }),
  ],
});