デバイスフローの有効化
はじめに
いわゆる「デバイスフロー」は、Web ブラウザ非搭載のデバイスや、文字入力が困難なデバイスが API クライアントとなる場合に、ユーザーの承認に基づいてアクセストークンを発行する認可フローです。RFC 8628 (OAuth 2.0 Device Authorization Grant) によって定義されています。
本記事では、Authlete を用いたデバイスフロー対応認可サーバーの構成と、Authlete の設定手順について説明します。
Authlete API を用いた認可サーバーのデバイスフロー対応
認可サーバーがデバイスフローに対応するためには、以下のエンドポイントおよび「検証 URI」の、新設・改修が必要です。これらを実装するための機能を、Authlete は API として提供しています。
- デバイス認可エンドポイント
- クライアントから受信した「デバイス認可リクエスト」を処理
- Authlete API: /device/authorization
- トークンエンドポイント
- クライアントから受信した「デバイスアクセストークンリクエスト」を処理
- Authlete API: /auth/token
- 「検証 URI」
- エンドユーザーから提示された “user_code” を処理し、必要に応じてユーザー認証・同意確認を実施
- Authlete API: /device/verification, /device/complete
Authlete の設定
本セクションではデバイスフローに対応するための設定を説明します。Authlete サービスと、同フローを用いるクライアントの、両方の設定が必要です。
Authlete サービスの設定
管理者コンソールから以下の項目を設定します。
タブ |
項目 |
設定内容 |
認可 |
サポートする認可種別 |
DEVICE_CODE を有効化 |
デバイスフロー |
デバイス認可エンドポイント |
デバイス認可エンドポイントの URL 例: https://as.example.com/device_authorization |
デバイスフロー |
検証 URI |
エンドユーザーに提示する verification_uri の値 例: https://as.example.com/device |
デバイスフロー |
プレースホルダー付き検証 URI |
エンドユーザーに(一般的には QR コード等を用いて)提示する verification_uri_complete の値 例: https://as.example.com/device?user_code=USER_CODE |
デバイスフロー |
検証コード有効期間 |
デバイス検証コード (device_code) とユーザー検証コード (user_code) の有効期間秒数 例: 600 |
デバイスフロー |
ポーリング間隔 |
トークンエンドポイントへのポーリングリクエスト間の最小秒数 例: 5 |
デバイスフロー |
ユーザーコード文字セット |
生成する user_code の文字セット 例: BASE20 |
デバイスフロー |
ユーザーコード長 |
生成する user_code の文字数 例: 8 |


クライアントの設定
クライアントアプリ開発者コンソールにアクセスし、以下の項目を設定します。
タブ |
項目 |
設定内容 |
基本情報 |
クライアントタイプ |
PUBLIC を選択 |
認可 |
認可種別 |
DEVICE_CODE を有効化 |
認可 |
[トークンエンドポイント] クライアント認証方式 |
NONE を選択 |
実行例
以下は、クライアントからのデバイス認可リクエストを起点に、エンドユーザーから提示された user_code の検証を行い、クライアントからのトークンリクエストに対して応答する例です。

デバイス認可リクエスト
ここでは、クライアントが認可サーバーに対して以下の「デバイス認可リクエスト」を送信したとします(手順 #2)。(以下の例はいずれも、読みやすさのために折り返しています)
POST /device_authorization HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded ... client_id=...&scope=openid+profile+read
- リクエスト(手順 #3。curl コマンドによる実行例)
curl -s -X POST $apiUrl/device/authorization -u $apiKey:$apiSecret -H 'Content-type: application/json' -d '{"parameters": "client_id=...&scope=openid+profile+read"}'
- レスポンス(手順 #4)
{ "type": "deviceAuthorizationResponse", "resultCode": "A220001", "resultMessage": "[A220001] The device authorization request was processed successfully.", "action": "OK", "deviceCode": "-jxwQ_7MEdR3SqS86bEg1ONUYdwGmSYjqH8eIBZ1c3U", "responseContent": "{\"user_code\":\"TXBBPHDZ\", \"device_code\": \"-jxwQ_7MEdR3SqS86bEg1ONUYdwGmSYjqH8eIBZ1c3U\", \"interval\":5, \"verification_uri_complete\": \"https://as.example.com/device?user_code=TXBBPHDZ\", \"verification_uri\": \"https://as.example.com/device\", \"expires_in\":600}", "userCode": "TXBBPHDZ", "verificationUri": "https://as.example.com/device", "verificationUriComplete": "https://as.example.com/device?user_code=TXBBPHDZ", ... }
認可サーバーは Authlete から返却された "responseContent" を、デバイス認可レスポンスの内容として、クライアントに返却します(手順 #5。詳細は省略)。
「検証 URI」
user_code の検証
クライアントは、認可サーバーから返却されたレスポンスに含まれる "device_code" の値を用いて、認可サーバーに対し、「デバイスアクセストークンリクエスト」を送信します(後述)。
その一方、同じくレスポンスから取得した "user_code" の値を、認可サーバーの「検証 URI」に提示するよう、エンドユーザーに促します(手順 #6)。
どのように提示するかはクライアントに任されています。以下は、先のレスポンスに含まれる "verification_uri" の値と共に、エンドユーザーに示す例 (RFC 8628 の例に加筆) です。
+-----------------------------------------------+ | | | Using a browser on another device, visit: | | https://as.example.com/device | | | | And enter the code: | | TXBBPHDZ | | | +-----------------------------------------------+
また以下は、同じくレスポンスに含まれる "verification_uri_complete" の値を QR コードにエンコードし、エンドユーザーにスキャンしてもらう例 (RFC 8628 の例に加筆) です。
+-------------------------------------------------+ | | | Scan the QR code or, using +------------+ | | a browser on another device, |[_].. . [_]| | | visit: | . .. . .| | | https://as.example.com/device | . . . ....| | | |. . . . | | | And enter the code: |[_]. ... . | | | TXBBPHDZ +------------+ | | | +-------------------------------------------------+
なんらかの方法でエンドユーザーから user_code を受け取った認可サーバーの「検証 URI」では(手順 #7)、Authlete の /device/verification API に user_code を転送し、処理を依頼します(手順 #8, 9)。
- リクエスト(手順 #8。curl コマンドによる実行例)
curl -s -X POST $apiUrl/device/verification -u $apiKey:$apiSecret -H 'Content-type: application/json' -d '{"userCode":"TXBBPHDZ"}
- レスポンス(手順 #9)
{ "type": "deviceVerificationResponse", "resultCode": "A224001", "resultMessage": "[A224001] The user code is valid.", "action": "VALID", "claimNames": [ ... ], "clientId": ..., "clientName": "Demo Client", "scopes": [ { "defaultEntry": false, "name": "openid" }, { "defaultEntry": false, "name": "profile" }, "defaultEntry": false, "name": "read" } ], ... }
このレスポンスには、user_code の値の検証に成功したことの他に、アクセストークンを要求しているクライアントの情報や、どのようなスコープやクレームを求めているかといった情報が含まれています。
認可サーバーはこれらをもとに、エンドユーザーに同意確認を行うことになります。
認可サーバーはこれらをもとに、エンドユーザーに同意確認を行うことになります。
検証完了
必要に応じて認可サーバーは、エンドユーザーを認証し、上記の情報から「どのクライアントがどのようなアクセス権を要求しているか」をエンドユーザーに提示します(手順 #10, 11)。
そしてエンドユーザーのユーザー識別子と、発行するトークンのプロパティ(スコープやクレームなど)が確定した段階で、Authlete の /device/complete API を呼び出し、処理を依頼します(手順 #12, 13)。
- リクエスト(手順 #12。curl コマンドによる実行例)
curl -s -X POST $apiUrl/device/complete -u $apiKey:$apiSecret -H 'Content-type: application/json' -d '{"userCode":"TXBBPHDZ", "result":"AUTHORIZED", "subject":"testuser01"}'
- レスポンス(手順 #13)
{ "type": "deviceCompleteResponse", "resultCode": "A241001", "resultMessage": "[A241001] The API call was processed successfully.", "action": "SUCCESS" }
この後認可サーバーは処理が完了した旨をエンドユーザーに示し、検証処理を終了します(手順 #14)。
トークンリクエスト
前述の通りクライアントは、 "device_code" の値を用いて、認可サーバーに対し「デバイスアクセストークンリクエスト」を送信します(手順 #a)。基本的には、user_code の検証が完了してアクセストークンが取得できるまで、繰り返しリクエストを行います(ポーリングします)。
- リクエスト(手順 #b。curl コマンドによる実行例)
curl -s -X POST $apiUrl/auth/token -u $apiKey:$apiSecret -H 'Content-type: application/json' -d '{"parameters": "client_id=... &grant_type=urn:ietf:params:oauth:grant-type:device_code &device_code=-jxwQ_7MEdR3SqS86bEg1ONUYdwGmSYjqH8eIBZ1c3U"}'
- レスポンス(手順 #c。user_code の検証完了前)
{ "type": "tokenResponse", "resultCode": "A242307", "resultMessage": "[A242307] The device authorization request has not been authorized yet.", "action": "BAD_REQUEST", "grantType": "DEVICE_CODE", "responseContent": "{\"error_description\": \"[A242307] The device authorization request has not been authorized yet.\", \"error\":\"authorization_pending\", \"error_uri\":\"https://docs.authlete.com/#A242307\"}", ... }
- レスポンス(手順 #c。user_code の検証完了後)
{ "type": "tokenResponse", "resultCode": "A242002", "resultMessage": "[A242002] The token request (grant_type=urn:ietf:params:oauth:grant-type:device_code) was processed successfully.", "accessToken": "ZJHO26vXTC1LIQXm9aYUFnMZd4R599aFA4hLBmH-OlM", "action": "OK", "clientId": ..., "grantType": "DEVICE_CODE", "idToken": "eyJhbGciOiJIUzI1NiJ9. eyJhdF9oYXNoIjoiZkpNOHhuODlTaVNQVnNsMGFLYnBTQSIsInN1YiI6InRlc3R1 c2VyMDEiLCJhdWQiOiIxNzIwMTA4MzE2NjE2MSIsImlzcyI6Imh0dHBzOi8vYXV0 aGxldGUuY29tIiwiZXhwIjoxNTk2NjE5OTk2LCJpYXQiOjE1OTY1MzM1OTZ9. OYuGqNbombW_DrSHsm9A07LZWa4UWyV_hSiSAQy-CYI", "refreshToken": "sliwK3Oa6Pag1c2aGenZALcGZXAP9cIiIu_zjGIdBCI", "responseContent": "{\"access_token\":\"ZJHO26vXTC1LIQXm9aYUFnMZd4R599aFA4hLBmH-OlM\", \"refresh_token\":\"sliwK3Oa6Pag1c2aGenZALcGZXAP9cIiIu_zjGIdBCI\", \"scope\":\"openid profile read\", \"id_token\": \"eyJhbGciOiJIUzI1NiJ9. eyJhdF9oYXNoIjoiZkpNOHhuODlTaVNQVnNsMGFLYnBTQSIsInN1YiI6InRlc3R1 c2VyMDEiLCJhdWQiOiIxNzIwMTA4MzE2NjE2MSIsImlzcyI6Imh0dHBzOi8vYXV0 aGxldGUuY29tIiwiZXhwIjoxNTk2NjE5OTk2LCJpYXQiOjE1OTY1MzM1OTZ9. OYuGqNbombW_DrSHsm9A07LZWa4UWyV_hSiSAQy-CYI\", \"token_type\":\"Bearer\", \"expires_in\":3600}", "scopes": [ "openid", "profile", "read" ], "subject": "testuser01", ... }
認可サーバーは "responseContent" の値を抽出し、クライアントに返却します(手順 #d)。
関連情報
- デバイスフロー (OAuth 2.0 Device Authorization Grant) では、デバイスフローの概要と、Authlete における同フローの対応について説明しています。
- シーケンス図テンプレートを、Authlete を用いたデバイスフローの設計にご活用ください。
- Authlete API リファレンスにて、認可サーバーにデバイスフローを実装するための API についての詳細情報を提供しています。
How did we do with this article?