mcpField
T
two-factor-authentication-best-practices

two-factor-authentication-best-practices

github.com/better-authセキュリティ22734.5k 回インストール8 週間前に更新
リポジトリ

two-factor-authentication-best-practices について

Better Auth に二要素認証を追加する開発者向けの実装ガイドです。TOTP、メールまたはSMSのOTP、バックアップコード、信頼済みデバイスとセキュリティ設定を扱います。

主な機能

  1. 01TOTP認証アプリの設定
  2. 02メールまたはSMSのOTP
  3. 03バックアップコードの生成と復旧
  4. 04信頼済みデバイスの管理
  5. 05コード保存とレート制限

活用シーン

  1. 01パスワード認証に追加確認を導入
  2. 02バックアップコードによるアカウント復旧
  3. 03OTPの送信方法と保存方法の設定
  4. 04信頼済みデバイスでのサインイン管理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/better-auth/skills --skill two-factor-authentication-best-practices

インストール後、Claude Code で/two-factor-authentication-best-practicesを入力して読み込まれたか確認します。

詳細

セットアップ

  1. issuer を指定して、サーバー設定に twoFactor() プラグインを追加します
  2. クライアント設定に twoFactorClient() プラグインを追加します
  3. npx auth@latest migrate を実行します(組み込みアダプター)。Drizzle/Prisma の場合は generate と push を実行します
  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 — generate a QR code from this
    // data.backupCodes — display to user
  }
};

最初の TOTP 検証が成功するまで、twoFactorEnabled は 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 or 8 digits (default: 6)
    period: 30, // Code validity period in seconds (default: 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, // Code validity in minutes (default: 3)
        digits: 6, // Number of digits (default: 6)
        allowedAttempts: 5, // Max verification attempts (default: 5)
      },
    }),
  ],
});
OTP の送信と検証

送信:authClient.twoFactor.sendOtp()。検証:authClient.twoFactor.verifyOtp({ code, trustDevice: true })。

OTP の保存時のセキュリティ

OTP コードをデータベースに保存する方法を設定します:

twoFactor({
  otpOptions: {
    storeOTP: "encrypted", // Options: "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>Save these codes in a secure location:</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 contains the new codes
};
アカウント復旧でのバックアップコードの使用
const verifyBackupCode = async (code: string) => {
  const { data, error } = await authClient.twoFactor.verifyBackupCode({
    code,
    trustDevice: true,
  });
};
バックアップコードの設定
twoFactor({
  backupCodeOptions: {
    amount: 10, // Number of codes to generate (default: 10)
    length: 10, // Length of each code (default: 10)
    storeBackupCodes: "encrypted", // Options: "plain", "encrypted"
  },
});

サインイン時の 2FA の処理

2FA が必要な場合、レスポンスに twoFactorRedirect: true が含まれます:

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

twoFactor({
  twoFactorCookieMaxAge: 600, // 10 minutes in seconds (default)
});
レート制限

組み込みの制限:すべての 2FA エンドポイントで 10 秒あたり 3 リクエスト。OTP には追加の試行回数制限があります:

twoFactor({
  otpOptions: {
    allowedAttempts: 5, // Max attempts per OTP code (default: 5)
  },
});
保存時の暗号化

TOTP シークレット:認証シークレットで暗号化されます。バックアップコード:デフォルトで暗号化されます。OTP:設定可能("plain"、"encrypted"、"hashed")。検証には定時間比較を使用します。

2FA を有効にできるのは、認証情報(メール/パスワード)アカウントのみです。

2FA を無効にする

パスワードの確認が必要です。信頼済みデバイスのレコードを取り消します:

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

完全な設定例

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

コメント