# 機能設計書 59-認証ID管理

## 概要

本ドキュメントは、Medusa ECプラットフォームにおける認証ID管理機能の設計を記述する。認証IDの作成・取得・更新・削除機能の詳細仕様を定義する。

### 本機能の処理概要

認証ID管理機能は、ユーザーの認証情報を管理するAuthIdentityエンティティのCRUD操作を提供する機能である。AuthIdentityは複数のProviderIdentity（外部認証プロバイダーとの紐付け）を持つことができ、OAuth等の外部認証と連携する基盤となる。また、認証（authenticate）、登録（register）、コールバック検証（validateCallback）等の認証フローも管理する。

**業務上の目的・背景**：ECサイトでは管理者、顧客の認証が必要であり、パスワード認証に加えてGoogle、Facebook等のOAuth認証にも対応する必要がある。認証ID管理は、これらの複数の認証方式を統一的に管理するための基盤機能である。

**機能の利用シーン**：
1. 管理者ログイン時の認証処理
2. 顧客ログイン時の認証処理
3. OAuth認証時のコールバック処理
4. 新規ユーザー登録時のAuthIdentity作成

**主要な処理内容**：
1. AuthIdentityの作成・更新・削除
2. ProviderIdentityの作成・更新
3. 認証処理（authenticate）
4. 登録処理（register）
5. OAuthコールバック検証（validateCallback）

**関連システム・外部連携**：外部OAuth認証プロバイダー（Google、GitHub等）と連携する。ユーザーモジュール、顧客モジュールと密接に連携する。

**権限による制御**：認証ID管理はシステム内部で使用され、直接のAPI公開は限定的。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ログイン画面 | 主機能 | 管理者のログイン認証処理 |
| 2 | パスワードリセット画面 | 主機能 | パスワードリセットリンクの送信・検証 |

## 機能種別

CRUD操作 / 認証処理

## 入力仕様

### 入力パラメータ

#### AuthIdentity作成

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| provider_identities | object[] | No | プロバイダーID情報の配列 | - |
| provider_identities[].entity_id | string | Yes | プロバイダー側のエンティティID | - |
| provider_identities[].provider | string | Yes | プロバイダー名 | - |
| provider_identities[].provider_metadata | object | No | プロバイダー固有のメタデータ | - |
| provider_identities[].user_metadata | object | No | ユーザー固有のメタデータ | - |
| app_metadata | object | No | アプリケーションメタデータ | - |

#### 認証処理

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| provider | string | Yes | 認証プロバイダー名 | - |
| authenticationData | AuthenticationInput | Yes | 認証データ | - |
| authenticationData.body | object | No | リクエストボディ | - |
| authenticationData.query | object | No | クエリパラメータ | - |

### 入力データソース

- リクエストパラメータ（API経由）
- 認証プロバイダーからのコールバック

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| AuthIdentityDTO | object | 認証ID情報 |
| id | string | AuthIdentityのID（authidプレフィックス） |
| provider_identities | ProviderIdentityDTO[] | プロバイダーID情報の配列 |
| app_metadata | object | アプリケーションメタデータ |
| AuthenticationResponse | object | 認証結果 |
| success | boolean | 認証成功フラグ |
| authIdentity | AuthIdentityDTO | 認証成功時のAuthIdentity |
| error | string | 認証失敗時のエラーメッセージ |

### 出力先

- API レスポンス（JSON形式）
- 認証トークン生成処理

## 処理フロー

### 処理シーケンス

```
1. 認証リクエスト受信
   └─ authenticate()を呼び出し
2. プロバイダーサービス呼び出し
   └─ authProviderService_.authenticate()に委譲
3. AuthIdentityProviderService取得
   └─ getAuthIdentityProviderService()で内部サービスを取得
4. プロバイダー固有の認証処理
   └─ 外部プロバイダーで認証実行
5. 結果の返却
   └─ AuthenticationResponseを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[認証リクエスト受信]
    B --> C[provider名を取得]
    C --> D[AuthIdentityProviderService取得]
    D --> E[authProviderService_.authenticate呼び出し]
    E --> F{認証成功?}
    F -->|Yes| G[AuthIdentityDTO返却]
    F -->|No| H[エラーメッセージ返却]
    G --> I[success: true]
    H --> J[success: false, error]
    I --> K[終了]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | entity_idユニーク | 同一プロバイダー内でentity_idは一意 | ProviderIdentity作成時 |
| BR-59-02 | 複数AuthIdentity禁止 | 同一entity_idで複数のAuthIdentityは作成不可 | AuthIdentity検索時 |
| BR-59-03 | カスケード削除 | AuthIdentity削除時にProviderIdentityも削除 | AuthIdentity削除時 |
| BR-59-04 | IDプレフィックス | AuthIdentityのIDはauthidプレフィックス | AuthIdentity作成時 |
| BR-59-05 | キャッシュ必須（OAuth） | OAuth認証時はキャッシュモジュールが必須 | setState/getState使用時 |

### 計算ロジック

```typescript
// 認証処理
async authenticate(
  provider: string,
  authenticationData: AuthenticationInput
): Promise<AuthenticationResponse> {
  try {
    return await this.authProviderService_.authenticate(
      provider,
      authenticationData,
      this.getAuthIdentityProviderService(provider)
    )
  } catch (error) {
    return { success: false, error: error.message }
  }
}

// AuthIdentityProviderService取得
getAuthIdentityProviderService(provider: string): AuthIdentityProviderService {
  return {
    retrieve: async ({ entity_id }) => {
      const authIdentities = await this.authIdentityService_.list({
        provider_identities: { entity_id, provider }
      }, { relations: ["provider_identities"] })
      // 存在チェック、一意性チェック
      return await this.baseRepository_.serialize(authIdentities[0])
    },
    create: async (data) => {
      const normalizedRequest = {
        provider_identities: [{
          entity_id: data.entity_id,
          provider_metadata: data.provider_metadata,
          user_metadata: data.user_metadata,
          provider,
        }]
      }
      const createdAuthIdentity = await this.authIdentityService_.create(normalizedRequest)
      return await this.baseRepository_.serialize(createdAuthIdentity)
    },
    update: async (entity_id, data) => { /* 更新処理 */ },
    setState: async (key, value) => { this.cache_.set(key, value, 1200) },
    getState: async (key) => { return await this.cache_.get(key) }
  }
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| AuthIdentity作成 | auth_identity | INSERT | AuthIdentityの新規作成 |
| ProviderIdentity作成 | provider_identity | INSERT | ProviderIdentityの新規作成 |
| AuthIdentity更新 | auth_identity | UPDATE | AuthIdentityの更新 |
| ProviderIdentity更新 | provider_identity | UPDATE | ProviderIdentityの更新 |
| AuthIdentity削除 | auth_identity | DELETE | カスケードでProviderIdentityも削除 |

### テーブル別操作詳細

#### auth_identity

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, app_metadata | リクエストパラメータから | idはauthidプレフィックス |
| SELECT | id, app_metadata, provider_identities | WHERE provider_identities.entity_id = :entityId AND provider_identities.provider = :provider | リレーション含む |
| UPDATE | app_metadata | WHERE id = :id | - |
| DELETE | - | WHERE id = :id | カスケード削除 |

#### provider_identity

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, entity_id, provider, auth_identity_id, user_metadata, provider_metadata | リクエストパラメータから | - |
| SELECT | id, entity_id, provider, user_metadata, provider_metadata | WHERE entity_id = :entityId AND provider = :provider | - |
| UPDATE | user_metadata, provider_metadata | WHERE id = :id | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------)|
| NOT_FOUND | MedusaError | entity_idでAuthIdentityが見つからない | 正しいentity_idを指定 |
| INVALID_DATA | MedusaError | 同一entity_idで複数のAuthIdentityが存在 | データ整合性を確認 |
| INVALID_ARGUMENT | MedusaError | OAuth使用時にキャッシュモジュールが未設定 | キャッシュモジュールを設定 |

### リトライ仕様

認証処理は冪等性があるため、ネットワークエラー時はリトライ可能。OAuth状態管理はキャッシュに保存（TTL: 20分）。

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

AuthIdentity、ProviderIdentityの作成・更新は@InjectManagerデコレータによりトランザクション管理される。

## パフォーマンス要件

- 認証処理: 100ms以内（外部プロバイダー除く）
- AuthIdentity作成: 50ms以内
- インデックス: IDX_provider_identity_provider_entity_idを使用

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

- 認証: APIエンドポイントでの認証は不要（認証処理自体のため）
- 認可: 内部サービスとして使用
- 状態管理: OAuthの状態はキャッシュに20分間保存
- メタデータ: provider_metadataには機密情報を保存可能

## 備考

- authidプレフィックスでAuthIdentityを識別
- カスケード削除でprovider_identitiesも自動削除
- OAuth認証時はキャッシュモジュールの依存が必要

---

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

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

### 推奨読解順序

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

まず、認証に関連するデータモデルを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | auth-identity.ts | `packages/modules/auth/src/models/auth-identity.ts` | AuthIdentityの構造、provider_identitiesリレーションを確認 |
| 1-2 | provider-identity.ts | `packages/modules/auth/src/models/provider-identity.ts` | ProviderIdentityの構造、entity_id, providerを確認 |

**読解のコツ**: カスケード削除の設定に注目。AuthIdentity削除時にprovider_identitiesも削除される。

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

認証モジュールのメインサービスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | auth-module.ts | `packages/modules/auth/src/services/auth-module.ts` | AuthModuleServiceの実装 |

**主要処理フロー**:
1. **74-100行目**: createAuthIdentities - AuthIdentityの作成
2. **115-133行目**: updateAuthIdentities - AuthIdentityの更新
3. **135-148行目**: register - ユーザー登録処理
4. **227-240行目**: authenticate - 認証処理
5. **242-255行目**: validateCallback - OAuthコールバック検証
6. **257-407行目**: getAuthIdentityProviderService - プロバイダーサービス取得

#### Step 3: プロバイダーサービスを理解する

認証プロバイダーとの連携を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | auth-provider.ts | `packages/modules/auth/src/services/auth-provider.ts` | AuthProviderServiceの実装 |

**主要処理フロー**:
- **52-59行目**: authenticate - プロバイダーでの認証
- **61-68行目**: register - プロバイダーでの登録
- **79-89行目**: validateCallback - コールバック検証

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

```
AuthModuleService.authenticate()
    │
    ├─ getAuthIdentityProviderService()
    │      ├─ retrieve() - AuthIdentityの取得
    │      ├─ create() - AuthIdentityの作成
    │      ├─ update() - ProviderIdentityの更新
    │      ├─ setState() - キャッシュに状態保存
    │      └─ getState() - キャッシュから状態取得
    │
    └─ authProviderService_.authenticate()
           └─ retrieveProviderRegistration()
                  └─ providerHandler.authenticate()

AuthModuleService.createAuthIdentities()
    │
    └─ authIdentityService_.create()
           └─ baseRepository_.serialize()
```

### データフロー図

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

provider        ───▶ getAuthIdentityProvider() ───▶ AuthIdentityProviderService
authenticationData   Service()

        │
        ▼
AuthIdentity    ───▶ authProviderService_     ───▶ AuthenticationResponse
ProviderService      .authenticate()                { success, authIdentity }

        │
        ▼
entity_id       ───▶ authIdentityService_.list() ───▶ AuthIdentityDTO
provider             baseRepository_.serialize()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| auth-module.ts | `packages/modules/auth/src/services/auth-module.ts` | ソース | 認証モジュールのメインサービス |
| auth-provider.ts | `packages/modules/auth/src/services/auth-provider.ts` | ソース | 認証プロバイダーサービス |
| auth-identity.ts | `packages/modules/auth/src/models/auth-identity.ts` | ソース | AuthIdentityのデータモデル |
| provider-identity.ts | `packages/modules/auth/src/models/provider-identity.ts` | ソース | ProviderIdentityのデータモデル |
