# 画面設計書 4-MFA認証画面

## 概要

本ドキュメントはInvenTreeシステムのMFA認証画面の設計仕様を記載する。二要素認証を行うための画面である。

### 本画面の処理概要

MFA認証画面は、ログイン時に二要素認証（Multi-Factor Authentication）が必要なユーザーに対して、追加の認証コードを入力させるための画面である。TOTP（Time-based One-Time Password）コード、リカバリーコード、またはWebAuthn（セキュリティキー）による認証をサポートする。

**業務上の目的・背景**：ユーザー名とパスワードだけでなく、追加の認証要素を要求することでセキュリティを強化する。不正アクセスや認証情報の漏洩によるリスクを軽減し、組織のセキュリティポリシーに準拠した認証フローを実現する。

**画面へのアクセス方法**：ログイン画面でユーザー名・パスワード認証が成功し、かつMFA認証が必要な場合に自動的にリダイレクトされる（401レスポンスでMFAフローが保留中の場合）。

**主要な操作・処理内容**：
1. TOTPコードまたはリカバリーコードの入力
2. 「このデバイスを記憶する」オプションの選択
3. ログインボタン押下による二要素認証の実行
4. WebAuthn対応時はセキュリティキーによる自動認証

**画面遷移**：
- 遷移元：ログイン画面（MFA必要時）
- 遷移先：ホーム画面（認証成功時）、MFA設定画面（MFA登録必要時）、ログイン画面（ログオフ時）

**権限による表示制御**：
- MFAタイプ（TOTP、リカバリーコード、WebAuthn）により表示内容が動的に変化
- WebAuthn対応時は自動的にセキュリティキー認証が開始される

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | 認証・ログイン | 主機能 | 二要素認証コードの入力・検証処理 |

## 画面種別

認証画面

## URL/ルーティング

| パス | 説明 |
|------|------|
| `/mfa` | MFA認証画面 |

## 入出力項目

### 入力項目

| No | 項目名 | 項目ID | 必須 | 型 | 最大長 | 説明 |
|----|--------|--------|------|-----|--------|------|
| 1 | TOTPコード | code | Yes | テキスト | - | 認証アプリから取得した6桁コードまたはリカバリーコード |
| 2 | このデバイスを記憶する | remember | No | チェックボックス | - | 30日間MFA入力をスキップするオプション |

### 出力項目

| No | 項目名 | 説明 |
|----|--------|------|
| 1 | エラーメッセージ | 認証失敗時のエラー内容 |
| 2 | 利用可能なMFAタイプ | サーバーから取得した認証方式の一覧 |

## 表示項目

| No | 項目名 | 表示条件 | 説明 |
|----|--------|----------|------|
| 1 | 画面タイトル | 常時 | "Multi-Factor Authentication" |
| 2 | TOTPコード入力欄 | TOTP/リカバリーコード対応時 | コード入力フィールド |
| 3 | このデバイスを記憶するチェックボックス | 常時 | 30日間記憶オプション |
| 4 | ログインボタン | 常時 | "Log in" ボタン |
| 5 | ログオフボタン | 常時 | 認証をキャンセルしてログアウト |
| 6 | エラーメッセージ | 認証失敗時 | エラー内容の表示 |

## イベント仕様

### 1-ログインボタン押下

TOTPコードを使用して二要素認証を実行する。

**処理フロー**：
1. `handleMfaLogin`関数を呼び出し
2. `POST /api/auth/v1/auth/2fa/authenticate` APIを呼び出し
3. 認証成功時：
   - ユーザー状態を取得
   - プロファイル設定を反映
   - グローバル状態を取得
   - リダイレクト先（元のページまたはホーム）へ遷移
4. セッション競合時（409）：
   - 「Already logged in / There is a conflicting session...」通知を表示
5. MFAトラスト保留時（401）：
   - `POST /api/auth/v1/auth/2fa/trust` APIを呼び出し
   - デバイス信頼設定を保存（rememberオプションに基づく）
6. 認証失敗時：
   - エラーメッセージを表示

### 2-WebAuthn自動認証

画面マウント時にWebAuthn対応であれば自動的にセキュリティキー認証を開始する。

**処理フロー**：
1. `useEffect`でMFAタイプをチェック
2. webauthnまたはwebauthn_2faが含まれる場合、`handleWebauthnLogin`を呼び出し
3. `GET /api/auth/v1/auth/webauthn/authenticate` でチャレンジを取得
4. ブラウザのWebAuthn APIでセキュリティキー認証を実行
5. `POST /api/auth/v1/auth/webauthn/authenticate` で認証完了
6. 成功時：通常のログイン成功処理を実行
7. MFAトラスト保留時：トラスト設定APIを呼び出し

### 3-ログオフボタン押下

認証をキャンセルしてログアウトする。

**処理フロー**：
1. `doLogout`関数を呼び出し
2. セッションを終了
3. ログイン画面へ遷移

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| MFA認証成功 | auth_session | UPDATE | セッションのMFA認証フラグ更新 |
| デバイス信頼設定 | mfa_trust | INSERT | 30日間のデバイス信頼情報保存 |

### テーブル別更新項目詳細

#### mfa_trust（デバイス信頼設定時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | 認証されたユーザーID | 外部キー |
| INSERT | device_token | デバイス識別トークン | 自動生成 |
| INSERT | expires_at | 作成日時 + 30日 | 有効期限 |

## メッセージ仕様

| No | メッセージID | メッセージ種別 | メッセージ内容 | 表示条件 |
|----|-------------|---------------|---------------|----------|
| 1 | mfa-success | 成功 | MFA Login successful / MFA details were automatically provided | 自動ログイン成功時 |
| 2 | session-conflict | エラー | Already logged in / There is a conflicting session... | セッション競合時（409） |
| 3 | mfa-error | エラー | An error occurred / {エラー詳細} | 認証失敗時 |

## 例外処理

| No | 例外条件 | 処理内容 |
|----|----------|----------|
| 1 | セッション競合（409） | 競合通知を表示、ログアウトを促す |
| 2 | MFAトラスト保留（401） | トラストAPIを呼び出し、認証を続行 |
| 3 | 認証コード不正 | エラーメッセージを表示 |
| 4 | WebAuthn認証失敗 | コンソールにエラー出力、手動入力にフォールバック |

## 備考

- MFAタイプは`recovery_codes`、`totp`、`webauthn`、`webauthn_2fa`がサポートされている
- WebAuthn認証は対応ブラウザとセキュリティキーが必要
- デバイス信頼設定により、30日間同じデバイスからのMFA入力をスキップ可能
- MFAコンテキストはサーバーAPI状態に保存されている

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

MFA認証に関連する状態とデータ型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ServerApiState.tsx | `src/frontend/src/states/ServerApiState.tsx` | `mfa_context`の状態管理、MFAタイプ情報 |
| 1-2 | ApiEndpoints.tsx | `src/frontend/lib/enums/ApiEndpoints.tsx` | `auth_login_2fa`, `auth_trust`, `auth_webauthn_login`エンドポイント |
| 1-3 | Auth.ts | `src/frontend/lib/types/Auth.ts` | `FlowEnum`の定義（MfaAuthenticate, MfaTrust等） |

**読解のコツ**: MFAコンテキストの`types`配列がどのMFA方式が利用可能かを示すことを理解する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MFA.tsx | `src/frontend/src/pages/Auth/MFA.tsx` | MFA認証画面のメインコンポーネント |

**主要処理フロー**:
1. **行12-20**: 状態初期化（フォーム、ナビゲート、MFAコンテキスト取得）
2. **行22-26**: WebAuthn対応時の自動認証開始（useEffect）
3. **行28-56**: JSX描画（コード入力、チェックボックス、ログインボタン）

#### Step 3: MFA認証処理関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | auth.tsx | `src/frontend/src/functions/auth.tsx` | `handleMfaLogin`, `handleWebauthnLogin`関数 |

**主要処理フロー**:
- **行357-406**: `handleMfaLogin`関数
  - 行365-370: 2FA認証API呼び出し
  - 行371-372: 成功時の処理
  - 行373-405: エラーハンドリング（セッション競合、MFAトラスト）
- **行734-786**: `handleWebauthnLogin`関数
  - 行740-747: WebAuthnチャレンジ取得
  - 行753-781: セキュリティキー認証とトラスト処理

#### Step 4: 認証成功後の処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | auth.tsx | `src/frontend/src/functions/auth.tsx` | `handleSuccessFullAuth`関数 |

**主要処理フロー**:
- **行465-496**: 認証成功後の共通処理
  - 認証コンテキスト設定
  - MFA設定確認
  - ユーザー状態取得
  - プロファイル反映
  - リダイレクト

### プログラム呼び出し階層図

```
MFA.tsx (エントリーポイント)
    │
    ├─ useForm() (code, remember)
    │
    ├─ useServerApiState (mfa_context)
    │      └─ mfa_types配列
    │
    ├─ useEffect() [WebAuthn自動認証]
    │      └─ handleWebauthnLogin()
    │             ├─ GET auth/webauthn/authenticate (チャレンジ取得)
    │             ├─ WebAuthn API (ブラウザ)
    │             └─ POST auth/webauthn/authenticate (認証)
    │
    ├─ TextInput (TOTPコード入力)
    │
    ├─ Checkbox (デバイス記憶)
    │
    ├─ Button (Log in)
    │      └─ handleMfaLogin()
    │             ├─ POST auth/2fa/authenticate
    │             ├─ handleSuccessFullAuth() [成功時]
    │             └─ POST auth/2fa/trust [トラスト保留時]
    │
    └─ Wrapper (logOff=true)
           └─ doLogout()
```

### データフロー図

```
[入力]                     [処理]                              [出力]

TOTPコード ──────────▶ handleMfaLogin()
remember ─────────────▶      │
                            ├─ POST auth/2fa/authenticate ───▶ 認証結果
                            │
                            ├─ 成功時 ────────────────────────▶ handleSuccessFullAuth()
                            │                                      │
                            │                                      ├─ fetchUserState()
                            │                                      ├─ observeProfile()
                            │                                      └─ /home へ遷移
                            │
                            ├─ トラスト保留時
                            │      └─ POST auth/2fa/trust ────▶ デバイス信頼設定
                            │
                            └─ 失敗時 ────────────────────────▶ エラー表示

WebAuthn対応時 ─────▶ handleWebauthnLogin()
(自動実行)                  │
                            ├─ GET auth/webauthn/authenticate ▶ チャレンジ取得
                            ├─ WebAuthn API ──────────────────▶ セキュリティキー認証
                            └─ POST auth/webauthn/authenticate ▶ 認証完了
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MFA.tsx | `src/frontend/src/pages/Auth/MFA.tsx` | ソース | MFA認証画面メインコンポーネント |
| auth.tsx | `src/frontend/src/functions/auth.tsx` | ソース | MFA認証関数（handleMfaLogin, handleWebauthnLogin） |
| Layout.tsx | `src/frontend/src/pages/Auth/Layout.tsx` | ソース | 認証画面レイアウト |
| ServerApiState.tsx | `src/frontend/src/states/ServerApiState.tsx` | ソース | MFAコンテキスト管理 |
| UserState.tsx | `src/frontend/src/states/UserState.tsx` | ソース | ユーザー状態管理 |
| ApiEndpoints.tsx | `src/frontend/lib/enums/ApiEndpoints.tsx` | ソース | APIエンドポイント定義 |
| router.tsx | `src/frontend/src/router.tsx` | ソース | ルーティング定義 |
