Device Flow
Device Flow (RFC 8628)
Device Flowは、Webブラウザを持たない、または入力機能が限られたデバイス(スマートTV、IoTデバイス、CLIツール)向けのOAuth 2.0拡張です。ユーザーは別のデバイス(スマートフォン/PC)で簡単な確認コードまたはQRコードを使用して認証します。
概要
- RFC: RFC 8628 - OAuth 2.0 Device Authorization Grant
- ステータス: 完全実装
- 対応エンドポイント:
/device_authorization,/device,/token - OIDC拡張: IDトークン発行をサポート
なぜDevice Flowを使用するのか?
主な利点
-
入力制限デバイス向け
- キーボードのないデバイス(スマートTV、ストリーミングボックス)に最適
- デバイスに組み込みWebブラウザ不要
- シンプルな8文字の確認コード(例:
WDJB-MJHT) - 即時スキャン用のQRコードサポート
-
セキュアな認証
- ユーザーは信頼できるデバイス(スマートフォン/PC)で認証
- PKCEサポート付きOAuth 2.0セキュリティモデル
- デバイスコードの1回限りの使用(リプレイ攻撃防止)
- 自動コード有効期限(デフォルト10分)
-
優れたユーザー体験
- TVリモコンでの複雑なURL入力不要
- QRコードをスキャンまたは短いコードを入力(8文字)
- 使い慣れたデバイス(電話/PC)で認証
ユースケース
- スマートTVアプリ(Netflix/YouTubeスタイルのログイン)
- IoTデバイス(スマートホームデバイス、セキュリティカメラ)
- CLIツール(GitHub CLI、AWS CLI、開発者ツール)
- ゲームコンソール(Xbox、PlayStationのログインフロー)
- キオスク端末(限られた入力を持つ公共端末)
仕組み
フロー概要
- デバイスが認可をリクエスト: デバイスが
POST /device_authorizationを送信 - サーバーがコードを返却:
device_code、user_code、verification_uriを返却 - デバイスがコードを表示: 画面にQRコードとユーザーコードを表示
- ユーザーが認証: ユーザーが電話/PCでURLにアクセスしてコードを入力
- デバイスがトークンをポーリング: デバイスが
/tokenエンドポイントをポーリング - サーバーがトークンを返却: ユーザー承認後、トークンを返却
APIリファレンス
1. デバイス認可エンドポイント
POST /device_authorization
リクエスト
POST /device_authorization HTTP/1.1Content-Type: application/x-www-form-urlencoded
client_id=tv_app_123&scope=openid+profile+emailレスポンス
{ "device_code": "4c9a8e6f-b2d1-4a7c-9e3f-1d2b4a7c9e3f", "user_code": "WDJB-MJHT", "verification_uri": "https://auth.example.com/device", "verification_uri_complete": "https://auth.example.com/device?user_code=WDJB-MJHT", "expires_in": 600, "interval": 5}| フィールド | 型 | 説明 |
|---|---|---|
device_code | string | ポーリング用UUID(秘密にする) |
user_code | string | ユーザー入力用8文字コード |
verification_uri | string | 手動コード入力用URL |
verification_uri_complete | string | コード事前入力済みURL |
expires_in | number | コード有効期限(秒) |
interval | number | 最小ポーリング間隔(秒) |
2. トークンエンドポイント(ポーリング)
POST /token
POST /token HTTP/1.1Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=4c9a8e6f-b2d1-4a7c-9e3f-1d2b4a7c9e3f&client_id=tv_app_123レスポンス状態
保留中(ポーリング継続):
{ "error": "authorization_pending", "error_description": "ユーザーはまだデバイスを認可していません"}速度超過(スローダウン):
{ "error": "slow_down", "error_description": "ポーリング頻度が高すぎます。スローダウンしてください。"}成功:
{ "access_token": "eyJhbGc...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "rt_...", "id_token": "eyJhbGc...", "scope": "openid profile email"}エラーコード:
authorization_pending- ユーザーがまだ承認していない(ポーリング継続)slow_down- ポーリングが速すぎる(間隔を5秒増加)access_denied- ユーザーがリクエストを拒否expired_token- デバイスコード期限切れ(フローを再開)
使用例
スマートTVアプリ統合
// Step 1: デバイスコードをリクエストconst response = await fetch('https://auth.example.com/device_authorization', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: 'smart_tv_app_123', scope: 'openid profile email' })});
const data = await response.json();// 表示: verification_uri_completeのQRコード// 表示: "コードを入力: WDJB-MJHT"
// Step 2: 認可をポーリングconst pollInterval = data.interval * 1000;let currentInterval = pollInterval;
const pollForAuthorization = async () => { const tokenResponse = await fetch('https://auth.example.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:device_code', device_code: data.device_code, client_id: 'smart_tv_app_123' }) });
if (tokenResponse.ok) { const tokens = await tokenResponse.json(); console.log('ログイン成功!', tokens); return tokens; }
const error = await tokenResponse.json();
if (error.error === 'authorization_pending') { setTimeout(pollForAuthorization, currentInterval); } else if (error.error === 'slow_down') { currentInterval += 5000; setTimeout(pollForAuthorization, currentInterval); } else { console.error('ログイン失敗:', error.error_description); }};
setTimeout(pollForAuthorization, currentInterval);CLIツール統合
$ awesome-cli login
デバイスログイン
アクセス: https://auth.example.com/device
コードを入力: WDJB-MJHT
またはこのQRコードをスキャン:
[QRコード]
認可を待っています...ログイン成功!認証されました。セキュリティ考慮事項
デバイスコードエントロピー
- UUID v4は122ビットのエントロピーを提供
- 推測攻撃を防止
コード有効期限
- デフォルト: 600秒(10分)
- Durable Objectアラームによる自動クリーンアップ
レート制限
- 最小間隔: 5秒(デフォルト)
- ポーリングが速すぎると
slow_downエラー - 最大ポーリング回数: 120回
1回限りの使用
- デバイスコードは最初の使用後に無効化
- リプレイ攻撃検出
ユーザーコード設計
- 文字セット:
23456789ABCDEFGHJKMNPQRSTUVWXYZ - 紛らわしい文字を除外:
0, O, 1, I, L - 形式:
XXXX-XXXX(読みやすさのためにハイフン)