コンテンツにスキップ

Device Flow

Device Flow (RFC 8628)

Device Flowは、Webブラウザを持たない、または入力機能が限られたデバイス(スマートTV、IoTデバイス、CLIツール)向けのOAuth 2.0拡張です。ユーザーは別のデバイス(スマートフォン/PC)で簡単な確認コードまたはQRコードを使用して認証します。

概要

なぜDevice Flowを使用するのか?

主な利点

  1. 入力制限デバイス向け

    • キーボードのないデバイス(スマートTV、ストリーミングボックス)に最適
    • デバイスに組み込みWebブラウザ不要
    • シンプルな8文字の確認コード(例:WDJB-MJHT
    • 即時スキャン用のQRコードサポート
  2. セキュアな認証

    • ユーザーは信頼できるデバイス(スマートフォン/PC)で認証
    • PKCEサポート付きOAuth 2.0セキュリティモデル
    • デバイスコードの1回限りの使用(リプレイ攻撃防止)
    • 自動コード有効期限(デフォルト10分)
  3. 優れたユーザー体験

    • TVリモコンでの複雑なURL入力不要
    • QRコードをスキャンまたは短いコードを入力(8文字)
    • 使い慣れたデバイス(電話/PC)で認証

ユースケース

  • スマートTVアプリ(Netflix/YouTubeスタイルのログイン)
  • IoTデバイス(スマートホームデバイス、セキュリティカメラ)
  • CLIツール(GitHub CLI、AWS CLI、開発者ツール)
  • ゲームコンソール(Xbox、PlayStationのログインフロー)
  • キオスク端末(限られた入力を持つ公共端末)

仕組み

フロー概要

  1. デバイスが認可をリクエスト: デバイスがPOST /device_authorizationを送信
  2. サーバーがコードを返却: device_codeuser_codeverification_uriを返却
  3. デバイスがコードを表示: 画面にQRコードとユーザーコードを表示
  4. ユーザーが認証: ユーザーが電話/PCでURLにアクセスしてコードを入力
  5. デバイスがトークンをポーリング: デバイスが/tokenエンドポイントをポーリング
  6. サーバーがトークンを返却: ユーザー承認後、トークンを返却

APIリファレンス

1. デバイス認可エンドポイント

POST /device_authorization

リクエスト

POST /device_authorization HTTP/1.1
Content-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_codestringポーリング用UUID(秘密にする)
user_codestringユーザー入力用8文字コード
verification_uristring手動コード入力用URL
verification_uri_completestringコード事前入力済みURL
expires_innumberコード有効期限(秒)
intervalnumber最小ポーリング間隔(秒)

2. トークンエンドポイント(ポーリング)

POST /token

POST /token HTTP/1.1
Content-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ツール統合

Terminal window
$ 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(読みやすさのためにハイフン)

参考資料