# 機能設計書 51-OAuth認証サーバー

## 概要

本ドキュメントは、Actual BudgetデスクトップアプリケーションにおけるOAuth認証サーバー機能の設計を記述する。この機能は、OpenID Connect認証フローにおけるコールバック処理を担当するローカルHTTPサーバーを提供する。

### 本機能の処理概要

Actual BudgetのElectronデスクトップアプリケーションにおいて、OpenID Connect認証を実現するためのローカルOAuth認証サーバーを構築・運用する機能である。外部のOpenIDプロバイダ（Google、Auth0等）からの認証コールバックを受け取り、アプリケーションに認証トークンを渡す中継役を担う。

**業務上の目的・背景**：従来のパスワード認証に加えて、企業向けシングルサインオン（SSO）を実現するため、OpenID Connect認証をサポートする必要がある。ユーザーは既存の企業認証基盤（Google Workspace、Azure AD等）を活用してActual Budgetにログインできるようになり、パスワード管理の負担軽減とセキュリティ強化を実現する。

**機能の利用シーン**：ユーザーがOpenID認証でログインを選択した際に、デスクトップアプリケーションが外部ブラウザを開き、認証プロバイダでの認証完了後、このローカルサーバーがコールバックを受け取る。

**主要な処理内容**：
1. ローカルHTTPサーバーをポート3010で起動
2. 外部認証プロバイダからのコールバックリクエストを受信
3. URLパラメータからトークンを抽出
4. Electronウィンドウを認証完了URLにリダイレクト
5. 認証完了後、サーバーを自動クローズ

**関連システム・外部連携**：OpenID Connectプロバイダ（Google、Auth0、Okta等）との連携が必要。デスクトップアプリケーションの同期サーバーとも連携する。

**権限による制御**：この機能自体に権限制御はないが、認証成功後にサーバーへのアクセス権限が付与される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | ログイン画面 | 主画面 | OpenID認証の開始トリガー |
| 3 | OpenIDコールバック画面 | 結果表示画面 | 認証完了後のリダイレクト先 |
| 4 | エラー画面 | 結果表示画面 | 認証失敗時の表示 |

## 機能種別

認証・認可処理 / サーバー起動・管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| token | string | Yes | OpenIDプロバイダから返却された認証トークン | 存在チェック |

### 入力データソース

外部OpenIDプロバイダからのHTTPリダイレクトリクエスト（GETメソッド）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| url | string | OAuthサーバーのURL（http://localhost:3010） |
| server | Server | HTTPサーバーインスタンス |

### 出力先

- Electronメインプロセス（IPCハンドラ経由）
- ブラウザへのレスポンス（テキスト形式）

## 処理フロー

### 処理シーケンス

```
1. start-oauth-server IPCイベント受信
   └─ createOAuthServer関数の呼び出し

2. 既存サーバーの存在チェック
   └─ 既に起動済みの場合は既存URLを返却

3. HTTPサーバーの作成
   └─ Node.js http.createServerで作成

4. サーバーのリッスン開始
   └─ ポート3010、ホスト127.0.0.1

5. コールバックリクエストの待機
   └─ GET /?token=xxx の形式

6. トークン受信時の処理
   ├─ URLパラメータからトークン抽出
   ├─ clientWinの存在確認
   ├─ 開発/本番環境に応じたリダイレクトURL構築
   └─ clientWin.loadURLでリダイレクト

7. レスポンス送信とクリーンアップ
   └─ 成功メッセージ送信後、サーバーをクローズ
```

### フローチャート

```mermaid
flowchart TD
    A[start-oauth-server IPC受信] --> B{既存サーバー存在?}
    B -->|Yes| C[既存URLを返却]
    B -->|No| D[HTTPサーバー作成]
    D --> E[ポート3010でリッスン開始]
    E --> F[URLとサーバーインスタンスを返却]
    F --> G[コールバック待機]
    G --> H{リクエスト受信}
    H --> I{トークンあり?}
    I -->|Yes| J{clientWin存在?}
    J -->|Yes| K[リダイレクトURL構築]
    K --> L[clientWin.loadURL実行]
    L --> M[成功レスポンス送信]
    M --> N[サーバークローズ]
    I -->|No| O[400エラーレスポンス]
    J -->|No| O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-1 | シングルインスタンス | OAuthサーバーは1インスタンスのみ起動可能 | サーバー起動時 |
| BR-51-2 | 自動クローズ | トークン受信後、サーバーは自動的にクローズされる | 認証完了時 |
| BR-51-3 | ローカルホスト限定 | セキュリティのため127.0.0.1のみでリッスン | 常時 |

### 計算ロジック

特になし

## データベース操作仕様

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

この機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | Bad Request | トークンパラメータなし | エラーメッセージを返却 |
| - | ポート競合 | ポート3010が使用中 | エラーログ出力 |

### リトライ仕様

リトライは実装されていない。ポート競合時は別途対応が必要。

## トランザクション仕様

トランザクション処理なし（データベース操作なし）

## パフォーマンス要件

- サーバー起動時間：1秒以内
- コールバック応答時間：100ms以内

## セキュリティ考慮事項

- ローカルホスト（127.0.0.1）のみでリッスンし、外部からのアクセスを防止
- 認証完了後は即座にサーバーをクローズ
- トークンはURLパラメータ経由で受け取るため、ログに残らないよう注意が必要

## 備考

- 開発モードと本番モードでリダイレクトURLが異なる
- Electron IPC経由でのみ起動可能

---

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

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

### 推奨読解順序

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

IPCイベントとサーバーの戻り値の型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/desktop-electron/index.ts` | 71行目：oAuthServer変数の型定義を確認 |

**読解のコツ**: Node.jsのhttp.Serverモジュールの型を理解しておくと、サーバーの動作が把握しやすい。

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

IPC通信経由でのサーバー起動処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/desktop-electron/index.ts` | 541-545行目：start-oauth-server IPCハンドラ |

**主要処理フロー**:
1. **541行目**: ipcMain.handle('start-oauth-server', ...)でIPCハンドラ登録
2. **542行目**: createOAuthServer()を呼び出し
3. **543行目**: oAuthServerにサーバーインスタンスを保持
4. **544行目**: URLを返却

#### Step 3: OAuthサーバー作成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/desktop-electron/index.ts` | 91-128行目：createOAuthServer関数 |

**主要処理フロー**:
- **92行目**: ポート3010を固定で使用
- **95-97行目**: 既存サーバーがあれば再利用
- **100行目**: createServerでHTTPサーバー作成
- **101-102行目**: URLパラメータからトークン抽出
- **104-111行目**: 開発/本番環境に応じたリダイレクトURL構築
- **117行目**: 認証完了後にサーバーをクローズ

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

```
ipcMain.handle('start-oauth-server')
    │
    └─ createOAuthServer()
           │
           ├─ http.createServer() [Node.js標準]
           │      │
           │      └─ リクエストハンドラ
           │             ├─ URL.searchParams.get('token')
           │             ├─ clientWin.loadURL()
           │             └─ server.close()
           │
           └─ server.listen(3010, '127.0.0.1')
```

### データフロー図

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

外部ブラウザ ───────▶ OpenIDプロバイダ ───────▶ コールバックリダイレクト
                                                        │
                                                        ▼
                                              OAuthサーバー(localhost:3010)
                                                        │
                                                        ▼
                                              トークン抽出・検証
                                                        │
                                                        ▼
                                              Electronウィンドウ ───▶ /openid-cb?token=xxx
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/desktop-electron/index.ts` | ソース | Electronメインプロセス、OAuth サーバー実装 |
| preload.js | `packages/desktop-electron/preload.js` | ソース | IPC通信のブリッジ |
| app-openid.js | `packages/sync-server/src/app-openid.js` | ソース | サーバー側OpenID認証処理 |
