# 画面設計書 337-デバイス認可

## 概要

本ドキュメントは、GitLabにおけるデバイス認可確認画面の設計仕様を定義する。

### 本画面の処理概要

デバイス認可確認画面は、OAuth2.0 Device Authorization Grant（デバイスフロー）において、ユーザーがデバイスへのアクセス権限を確認・承認するための画面である。

**業務上の目的・背景**：OAuth2.0 Device Authorization Grant（RFC 8628）は、入力能力が制限されたデバイス（スマートTV、IoTデバイス、CLIツールなど）向けの認可フローである。これらのデバイスではブラウザベースの認可フローが困難なため、ユーザーは別のデバイス（スマートフォンやPC）でGitLabにログインし、デバイスが表示するユーザーコードを入力して認可を行う。本画面は、このデバイス認可フローにおいて、ユーザーがデバイスを認可する最終確認を行うために必要である。

**画面へのアクセス方法**：
1. デバイスがGitLab Device Authorizationエンドポイントにリクエストを送信
2. デバイスがユーザーコードと認証URLを表示
3. ユーザーが別のデバイスでGitLabにログイン
4. ユーザーが `/oauth/device` にアクセスし、ユーザーコードを入力
5. 本確認画面が表示される

**主要な操作・処理内容**：
1. ユーザー情報の確認
2. 要求されているスコープの確認
3. デバイス認可の承認（Confirmボタン）

**画面遷移**：
- 遷移元：デバイス認可画面（ユーザーコード入力画面、No.10）
- 遷移先：認可成功画面、または認可エラー画面

**権限による表示制御**：
- ログインユーザーのみアクセス可能
- 管理者ユーザーには警告メッセージが追加表示される

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 88 | OAuth2プロバイダ | 主機能 | デバイス認可確認 |
| 76 | ユーザー登録 | 補助機能 | ユーザー認証状態の確認 |

## 画面種別

確認（認可承認）

## URL/ルーティング

| メソッド | パス | アクション |
|---------|------|-----------|
| GET | `/oauth/device/confirm` | `oauth/device_authorizations#confirm` |
| POST | `/oauth/device/authorizations/authorize` | デバイス認可の承認 |

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| user_code | 入力（hidden） | String | Yes | デバイスから受け取ったユーザーコード |

## 表示項目

| 項目名 | データソース | 表示形式 | 備考 |
|--------|-------------|---------|------|
| ページタイトル | 固定 | 見出し | "Authorize device to access to your GitLab account." |
| 説明文 | 固定 | サブテキスト | "Please make sure that you intended to authorize this device." |
| ユーザーアバター | current_user | アバターコンポーネント | 24pxサイズ |
| ユーザー名 | current_user.name | 太字テキスト | - |
| ユーザー参照 | current_user.to_reference | 薄いテキスト | @username形式 |
| 管理者警告 | 固定 | アラートコンポーネント | 管理者のみ表示 |
| スコープ一覧 | @scopes | テキスト | 要求されているスコープ |
| 確認ボタン | - | ボタン | Confirm |

## イベント仕様

### 1-確認ボタン（Confirm）

**トリガー**: 「Confirm」ボタンをクリック

**処理内容**:
1. フォームをPOST `/oauth/device/authorizations/authorize` に送信
2. hidden field `user_code` を含める
3. デバイス認可グラントを承認
4. 成功画面または結果をデバイスに通知

**エンドポイント**: Doorkeeper::DeviceAuthorizationGrant::DeviceAuthorizationsController#authorize

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | oauth_device_grants | SELECT | デバイスグラント情報の取得 |
| 確認ボタン | oauth_device_grants | UPDATE | グラント承認状態の更新 |
| 確認ボタン | oauth_access_tokens | INSERT | アクセストークンの生成 |

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

#### oauth_device_grants

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | scopes, application_id | WHERE user_code = :user_code | 確認画面表示用 |
| UPDATE | user_id | current_user.id | 認可承認時 |
| UPDATE | authorized_at | Time.current | 認可承認時 |

#### oauth_access_tokens

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | token | 生成されたアクセストークン | ハッシュ化 |
| INSERT | resource_owner_id | current_user.id | - |
| INSERT | application_id | グラントのapplication_id | - |
| INSERT | scopes | グラントのscopes | - |
| INSERT | expires_in | 設定値 | - |

## メッセージ仕様

| 種別 | メッセージID | メッセージ内容 | 表示条件 |
|------|-------------|---------------|---------|
| 見出し | DeviceAuth\|Authorize device... | Authorize device to access to your GitLab account. | 常時表示 |
| 説明 | DeviceAuth\|Please make sure... | Please make sure that you intended to authorize this device. | 常時表示 |
| 警告 | DeviceAuth\|You are an administrator... | You are an administrator, which means authorizing access will allow it to interact with GitLab as an administrator as well. | 管理者のみ |
| スコープ | DeviceAuth\|Scopes associated... | Scopes associated with this request: {scopes} | スコープ存在時 |
| ボタン | DeviceAuth\|Confirm | Confirm | 常時表示 |

## 例外処理

| 例外状況 | 処理内容 | 表示/遷移先 |
|---------|---------|------------|
| 無効なユーザーコード | エラー表示 | デバイス認可入力画面 |
| 期限切れのユーザーコード | エラー表示 | デバイス認可入力画面 |
| 未認証状態 | ログイン画面へリダイレクト | ログイン画面 |
| 既に使用済みのコード | エラー表示 | デバイス認可入力画面 |

## 備考

- デバイスフロー（RFC 8628）はOAuth2.0の拡張仕様
- ユーザーコードは通常、大文字英数字で構成され、入力しやすい形式
- デバイスはポーリングでアクセストークンを取得する
- 管理者ユーザーには特別な警告が表示され、管理者権限での操作が可能になることを明示
- `minimal` レイアウトで表示される
- Pajamas UIコンポーネント（Avatar、Alert、Button）を使用

---

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

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

### 推奨読解順序

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

デバイスグラントのデータモデルを理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Doorkeeper::DeviceAuthorizationGrant | Doorkeeper gem内 | デバイスグラントモデル |
| 1-2 | doorkeeper.rb | `config/initializers/doorkeeper.rb` | Doorkeeper設定 |

**読解のコツ**: Doorkeeper gemのDevice Authorization Grant拡張を使用している。`use_doorkeeper_device_authorization_grant`でルーティングが設定される。

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

コントローラの処理フローを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | device_authorizations_controller.rb | `app/controllers/oauth/device_authorizations_controller.rb` | デバイス認可コントローラ |

**主要処理フロー**:
1. **行7-14**: `index` - デバイス認可入力画面（ユーザーコード入力）
2. **行16-27**: `confirm` - 確認画面表示、スコープ取得
3. **行18**: `device_grant_model.find_by(user_code: user_code)` - グラント検索
4. **行20**: `@scopes = device_grant&.scopes` - スコープ取得

#### Step 3: ビューテンプレートを理解する

確認画面のUI構造。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | authorize.html.haml | `app/views/doorkeeper/device_authorization_grant/authorize.html.haml` | 確認画面テンプレート |

**主要処理フロー**:
- **行3-4**: 見出しと説明文
- **行7-13**: ユーザー情報表示（アバター、名前、参照）
- **行14-17**: 管理者警告（条件付き表示）
- **行19-22**: スコープ表示
- **行24-32**: 確認フォーム（hidden field + ボタン）

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

```
デバイス認可フロー
    │
    ├─ POST /oauth/device_authorization (Device側)
    │      └─ Doorkeeper::DeviceAuthorizationController#create
    │             └─ device_code, user_code, verification_uri を返却
    │
    ├─ GET /oauth/device (User側 - ユーザーコード入力)
    │      └─ DeviceAuthorizationsController#index
    │             └─ render "index"
    │
    ├─ GET /oauth/device/confirm?user_code=... (User側 - 確認画面)
    │      └─ DeviceAuthorizationsController#confirm
    │             ├─ device_grant_model.find_by(user_code: user_code)
    │             ├─ @scopes = device_grant.scopes
    │             └─ render "authorize"
    │
    └─ POST /oauth/device/authorizations/authorize (User側 - 認可承認)
           └─ Doorkeeper::DeviceAuthorizationGrant::DeviceAuthorizationsController#authorize
                  ├─ デバイスグラント承認
                  └─ アクセストークン生成準備
```

### データフロー図

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

user_code ───▶ DeviceAuthorizationsController#confirm
    │                      │
    │                      ├─ device_grant_model.find_by(user_code: ...)
    │                      │      └─ oauth_device_grants テーブル
    │                      │
    │                      ├─ @scopes = device_grant.scopes
    │                      │
    │                      └─ render authorize.html.haml ───▶ 確認画面
    │
    └─ Confirmボタン ───▶ authorize アクション
                               │
                               ├─ デバイスグラント承認
                               │
                               └─ デバイスがポーリングでアクセストークン取得可能に
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| device_authorizations_controller.rb | `app/controllers/oauth/device_authorizations_controller.rb` | コントローラ | デバイス認可制御 |
| authorize.html.haml | `app/views/doorkeeper/device_authorization_grant/authorize.html.haml` | テンプレート | 確認画面表示 |
| index.html.haml | `app/views/doorkeeper/device_authorization_grant/index.html.haml` | テンプレート | コード入力画面 |
| doorkeeper.rb | `config/initializers/doorkeeper.rb` | 設定 | Doorkeeper設定 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング（use_doorkeeper_device_authorization_grant） |
| AvatarComponent | `app/components/pajamas/avatar_component.rb` | コンポーネント | アバター表示 |
| AlertComponent | `app/components/pajamas/alert_component.rb` | コンポーネント | 警告表示 |
| ButtonComponent | `app/components/pajamas/button_component.rb` | コンポーネント | ボタン表示 |
