# 機能設計書 81-個人アクセストークン

## 概要

本ドキュメントは、GitLabにおける個人アクセストークン（Personal Access Token: PAT）機能の設計を記述する。個人アクセストークンは、API認証やGit操作に使用される認証トークンであり、ユーザーがパスワードを使用せずにGitLabリソースにアクセスするための仕組みを提供する。

### 本機能の処理概要

**業務上の目的・背景**：個人アクセストークンは、CI/CDパイプライン、外部ツール連携、スクリプト自動化など、パスワードを直接使用することが適切でない場面でのセキュアな認証手段を提供する。OAuth2認証が複雑すぎるユースケースや、単純なAPI呼び出しに対して軽量な認証メカニズムとして利用される。トークンにはスコープ（権限範囲）と有効期限を設定でき、セキュリティを担保しつつ柔軟なアクセス制御を実現する。

**機能の利用シーン**：
- CI/CDパイプラインからのAPI呼び出し認証
- 外部ツール（IDE、クライアントアプリ等）からのGitLab API連携
- スクリプトによる自動化タスク実行時の認証
- Git over HTTPSでのリポジトリ操作認証
- プロジェクト/グループアクセストークンとしてのボット認証

**主要な処理内容**：
1. 新規トークンの作成（名前、スコープ、有効期限を指定）
2. トークンの一覧表示と管理
3. トークンの取り消し（Revoke）
4. トークンのローテーション（旧トークンを無効化し新トークンを発行）
5. トークンの有効期限通知管理
6. ICSフィードによるトークン有効期限カレンダー出力

**関連システム・外部連携**：
- Doorkeeper（OAuth2）との統合認証
- 通知システム（トークン作成・取り消し・期限切れ通知）
- 監査ログシステム（トークン操作の記録）

**権限による制御**：
- ユーザーは自身のトークンのみ作成・管理可能
- 管理者は他ユーザーのトークン作成権限を持つ（impersonation token）
- スコープにより、トークンでアクセス可能なリソースを制限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 118 | アクセストークン一覧 | 主画面 | プロジェクトアクセストークンの管理 |
| 177 | アクセストークン一覧 | 主画面 | グループアクセストークンの管理 |
| 198 | アクセストークン一覧 | 主画面 | 個人アクセストークンの管理 |
| 199 | 新規アクセストークン | 主画面 | 新規アクセストークンの作成 |
| 263 | 偽装トークン一覧 | 主画面 | 偽装トークン管理（管理者用） |

## 機能種別

CRUD操作 / 認証・認可 / セキュリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | トークンの識別名 | 空でないこと |
| scopes | Array | Yes | 付与するスコープ（api, read_api等） | 有効なスコープのみ許可 |
| expires_at | Date | 条件付き | 有効期限（設定が必須の場合は必須） | 最大有効期限を超えないこと |
| description | String | No | トークンの説明 | - |
| impersonation | Boolean | No | 偽装トークンフラグ（管理者のみ） | - |
| granular | Boolean | No | 細粒度トークンフラグ | - |

### 入力データソース

- 画面入力（Personal Access Tokensコントローラー経由）
- API経由（REST API / GraphQL API）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| token | String | 生成されたトークン文字列（作成時のみ表示） |
| id | Integer | トークンID |
| name | String | トークン名 |
| scopes | Array | 付与されたスコープ |
| expires_at | Date | 有効期限 |
| created_at | DateTime | 作成日時 |
| last_used_at | DateTime | 最終使用日時 |
| revoked | Boolean | 取り消し状態 |

### 出力先

- 画面表示（トークン一覧、作成完了画面）
- ICSファイル（カレンダーフィード）
- API応答（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. トークン作成リクエスト受信
   └─ PersonalAccessTokensController#create
2. 権限チェック
   └─ creation_permitted?でcreate_user_personal_access_tokenポリシー確認
3. トークン生成
   └─ PersonalAccessToken.createでレコード作成・トークン文字列生成
4. 後処理
   └─ 作成ログ記録、イベントトラッキング、通知送信
5. 結果返却
   └─ 成功時：トークン文字列を含むレスポンス、失敗時：エラーメッセージ
```

### フローチャート

```mermaid
flowchart TD
    A[トークン作成リクエスト] --> B{作成権限あり?}
    B -->|No| C[エラー: Not permitted]
    B -->|Yes| D[有効期限チェック]
    D --> E{期限必須設定?}
    E -->|Yes| F[最大有効期限を適用]
    E -->|No| G[指定期限または無期限]
    F --> H[トークン生成]
    G --> H
    H --> I{保存成功?}
    I -->|No| J[バリデーションエラー返却]
    I -->|Yes| K[ログ記録]
    K --> L[イベントトラッキング]
    L --> M[通知送信]
    M --> N[成功レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-81-01 | 最大有効期限制限 | トークンの有効期限は365日（または400日）を超えられない | require_personal_access_token_expiryが有効時 |
| BR-81-02 | スコープ制限 | 付与可能なスコープはシステム定義のもののみ | 常時 |
| BR-81-03 | トークンプレフィックス | トークンは`glpat-`プレフィックスで始まる | 常時 |
| BR-81-04 | 取り消し済みトークン不可 | 取り消し済みトークンはローテーション不可 | ローテーション時 |
| BR-81-05 | 偽装トークン権限 | 偽装トークンは管理者のみ作成可能 | impersonation=true時 |

### 計算ロジック

**有効期限計算**：
- 明示的な指定がある場合：指定日付
- 指定なしかつ期限必須設定の場合：現在日 + max_expiration_lifetime_in_days

**ローテーション時の有効期限**：
- keep_token_lifetime=true の場合：旧トークンと同じ寿命を新トークンに適用
- それ以外：デフォルト1週間、または指定期限

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | personal_access_tokens | INSERT | 新規トークンレコード作成 |
| 取り消し | personal_access_tokens | UPDATE | revoked=true, updated_at更新 |
| ローテーション | personal_access_tokens | UPDATE/INSERT | 旧トークン取り消し＋新トークン作成 |
| 最終使用更新 | personal_access_tokens | UPDATE | last_used_at更新 |

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

#### personal_access_tokens

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | 対象ユーザーID | |
| INSERT | name | パラメータ指定値 | |
| INSERT | token_digest | トークンのSHA256ダイジェスト | 平文は保存しない |
| INSERT | scopes | パラメータ指定値 | Array型 |
| INSERT | expires_at | 計算された有効期限 | |
| INSERT | organization_id | 現在の組織ID | |
| UPDATE | revoked | true | 取り消し時 |
| UPDATE | last_used_at | 現在日時 | 認証使用時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | 作成権限なし | エラーメッセージ表示 |
| - | バリデーションエラー | 必須項目未入力、無効なスコープ | フォームエラー表示 |
| - | 有効期限エラー | 最大期限超過 | エラーメッセージ表示 |
| - | 取り消し済みエラー | 取り消し済みトークンのローテーション試行 | エラーメッセージ表示 |

### リトライ仕様

トークン生成処理は冪等ではないため、リトライは行わない。

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

- トークン作成：単一レコードINSERTのため明示的トランザクション不要
- ローテーション：旧トークン取り消しと新トークン作成をトランザクションで囲む（失敗時ロールバック）

## パフォーマンス要件

- トークン作成：1秒以内
- トークン検証：100ms以内（頻繁に呼び出されるため）
- 一覧取得：ページネーション適用

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

- トークン文字列は作成時のみ表示、データベースにはダイジェストのみ保存
- 有効期限の強制設定オプション（インスタンス設定）
- トークン操作は監査ログに記録
- 取り消し時は即座に無効化
- 通知による異常検知支援（作成・取り消し時のメール通知）

## 備考

- トークンプレフィックスはインスタンス設定でカスタマイズ可能
- Granular PAT（細粒度トークン）機能はフィーチャーフラグで制御
- DPoP（Demonstrating Proof of Possession）対応オプションあり

---

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

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

### 推奨読解順序

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

トークンのデータモデルを理解することが最初のステップである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | personal_access_token.rb | `app/models/personal_access_token.rb` | トークンモデルの定義、スコープ、バリデーション |

**読解のコツ**: Railsモデルの基本構造を理解していること。`TokenAuthenticatable`モジュールがトークン生成・検証ロジックを提供している。

**主要処理フロー**:
- **3-13行目**: モデルのinclude定義、使用するモジュールの確認
- **24-32行目**: `add_authentication_token_field`によるトークンフィールド定義
- **41行目**: スコープのシリアライズ定義
- **45-53行目**: アソシエーション定義（user, group, organization等）
- **60-94行目**: 各種スコープ定義（active, expired, revoked等）
- **96-101行目**: バリデーション定義
- **104-112行目**: `revoke!`メソッドの実装

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

トークン操作のエントリーポイントはコントローラーである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | personal_access_tokens_controller.rb | `app/controllers/user_settings/personal_access_tokens_controller.rb` | コントローラーアクション定義 |

**主要処理フロー**:
- **12-44行目**: `index`アクション - 一覧表示とICSフィード対応
- **50-64行目**: `create`アクション - トークン作成処理のエントリーポイント
- **85-100行目**: `expiry_ics` - 有効期限のICS形式出力

#### Step 3: サービス層を理解する

ビジネスロジックはサービス層に実装されている。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/personal_access_tokens/create_service.rb` | トークン作成ロジック |
| 3-2 | revoke_service.rb | `app/services/personal_access_tokens/revoke_service.rb` | トークン取り消しロジック |
| 3-3 | rotate_service.rb | `app/services/personal_access_tokens/rotate_service.rb` | トークンローテーションロジック |

**主要処理フロー（CreateService）**:
- **7-14行目**: コンストラクタ - パラメータ初期化
- **16-36行目**: `execute` - メイン処理フロー
- **42-52行目**: `personal_access_token_params` - パラメータ構築
- **66-68行目**: `creation_permitted?` - 権限チェック

**主要処理フロー（RevokeService）**:
- **20-30行目**: `execute` - 取り消し処理
- **42-51行目**: `revocation_permitted?` - 取り消し権限判定

**主要処理フロー（RotateService）**:
- **17-38行目**: `execute` - ローテーション処理（トランザクション内）
- **44-67行目**: `create_access_token` - 新トークン生成

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

```
PersonalAccessTokensController#create
    │
    ├─ PersonalAccessTokens::CreateService#execute
    │      ├─ creation_permitted? (Ability.allowed?)
    │      ├─ PersonalAccessToken.create
    │      ├─ log_event
    │      ├─ track_event
    │      └─ NotificationService#access_token_created
    │
PersonalAccessTokens::RevokeService#execute
    │
    ├─ revocation_permitted?
    ├─ PersonalAccessToken#revoke!
    ├─ log_event
    └─ NotificationService#access_token_revoked

PersonalAccessTokens::RotateService#execute
    │
    ├─ PersonalAccessToken#revoke! (旧トークン)
    ├─ create_access_token (新トークン)
    │      └─ PersonalAccessToken.create
    ├─ update_project_bot_membership
    └─ NotificationService#access_token_rotated
```

### データフロー図

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

ユーザー入力         CreateService                    DB保存
(name, scopes,   ──▶ ├─権限チェック            ──▶  personal_access_tokens
 expires_at)         ├─パラメータ構築
                     └─トークン生成

                                                      ▼
                                                   通知送信
                                                   (メール)
                                                      ▼
                                                   監査ログ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| personal_access_token.rb | `app/models/personal_access_token.rb` | モデル | トークンデータモデル |
| personal_access_tokens_controller.rb | `app/controllers/user_settings/personal_access_tokens_controller.rb` | コントローラー | Web UI用コントローラー |
| create_service.rb | `app/services/personal_access_tokens/create_service.rb` | サービス | 作成ロジック |
| revoke_service.rb | `app/services/personal_access_tokens/revoke_service.rb` | サービス | 取り消しロジック |
| rotate_service.rb | `app/services/personal_access_tokens/rotate_service.rb` | サービス | ローテーションロジック |
| last_used_service.rb | `app/services/personal_access_tokens/last_used_service.rb` | サービス | 最終使用日時更新 |
| notification_service.rb | `app/services/notification_service.rb` | サービス | 通知送信 |
