Laravel 12 + Fortify その6 Google AuthenticatorやMicrosoft Authenticatorに対応する

## はじめに

前回までの記事で、トークン認証やAPI連携まで解説しました。  
今回は、Laravel 12 + FortifyでGoogle AuthenticatorやMicrosoft AuthenticatorなどのTOTP形式（Time-based One-Time Password）の多要素認証（MFA）に対応する方法を紹介します。

---

## 1. Fortifyの2要素認証機能の有効化

Fortifyは標準で2要素認証（2FA）の仕組みを持っています。  
ただしデフォルトは「メールベース」ですが、カスタマイズによりTOTP（Google Authenticatorなど）にも対応できます。

`config/fortify.php` の `features` に二要素認証を追加します。

```php
'features' => [
    // ...他の機能
    Features::twoFactorAuthentication([
        'confirmPassword' => true,
    ]),
],
```

---

## 2. TOTP認証ライブラリの導入

Laravel標準の二要素認証はTOTP方式には未対応なので、  
**laravel-mfa** や **pragmarx/google2fa-laravel** などの外部パッケージを併用します。

ここでは例として「pragmarx/google2fa-laravel」を利用します。

```bash
composer require pragmarx/google2fa-laravel
```

---

## 3. UserモデルにTOTP用カラムを追加

マイグレーションを作成して、TOTPシークレットを保存するカラムを追加します。

```bash
php artisan make:migration add_google2fa_secret_to_users_table
```

マイグレーションファイル例：

```php
public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('google2fa_secret')->nullable();
    });
}
```

マイグレーションを実行：

```bash
php artisan migrate
```

---

## 4. シークレット生成・QRコード表示

ユーザーが設定画面からTOTPを有効化できるよう、コントローラとBladeを用意します。

### シークレット生成例（コントローラ）

```php
use PragmaRX\Google2FALaravel\Support\Authenticator;

public function enable2fa(Request $request)
{
    $user = $request->user();

    if (!$user->google2fa_secret) {
        $user->google2fa_secret = app('pragmarx.google2fa')->generateSecretKey();
        $user->save();
    }

    $QR_Image = app('pragmarx.google2fa')->getQRCodeInline(
        config('app.name'),
        $user->email,
        $user->google2fa_secret
    );

    return view('auth.2fa-setup', [
        'QR_Image' => $QR_Image,
        'secret' => $user->google2fa_secret,
    ]);
}
```

### Blade例（QRコードとシークレット表示）

```blade
<div>
    <h3>Google/Microsoft Authenticator連携</h3>
    <p>以下のQRコードをAuthenticatorアプリで読み取ってください。</p>
    <div>{!! $QR_Image !!}</div>
    <p>シークレットキー: <code>{{ $secret }}</code></p>
</div>
```

---

## 5. TOTPコード検証

ユーザーがログイン時に6桁コードを入力する画面を用意し、検証処理を追加します。

```php
public function verify2fa(Request $request)
{
    $user = $request->user();
    $valid = app('pragmarx.google2fa')->verifyKey(
        $user->google2fa_secret,
        $request->input('one_time_password')
    );
    if ($valid) {
        // セッションなどに2FA認証済みフラグをセット
        session(['2fa_passed' => true]);
        return redirect()->intended('/dashboard');
    } else {
        return back()->withErrors(['one_time_password' => '認証コードが無効です']);
    }
}
```

---

## 6. Fortifyのフローに組み込む

- ログイン後に2FAコード入力を必須にするには、Fortifyの`TwoFactorAuthenticatedSessionController`やカスタムミドルウェアで「2FA認証済みか」を判定し、未認証ならリダイレクトします。
- Fortify標準の2FA（メール/SMSコード）を「TOTPコード」入力画面に差し替えます。

---

## 7. まとめ

- Fortify標準機能＋外部パッケージでGoogle AuthenticatorやMicrosoft Authenticator対応の2FAが実現できる
- ユーザーごとにシークレットを生成し、TOTP認証を組み込む
- ビジネス/セキュリティ要件に応じて必須化やUIを工夫しよう

---

### 参考

- [pragmarx/google2fa-laravel](https://github.com/antonioribeiro/google2fa-laravel)
- [Laravel Fortify公式ドキュメント（二要素認証）](https://laravel.com/docs/12.x/fortify#two-factor-authentication)
- [Google Authenticatorアプリ公式](https://support.google.com/accounts/answer/1066447)