Device Authorization Grantやってみた

はじめに

この記事は認証認可技術 Advent Calendar 2019の4日目の記事です。

諸事情でOAuth 2.0 Device Authorization Grantを理解する必要があったので、お勉強した記録を整理しました。

概要を説明したあと、Googleの認可サーバーからcurlとブラウザでシュッとアクセストークンをとるところを書いています。

Device Authorization Grant is 何 ?

Device Authorization GrantのRFCはこちらです。現在、Proposed Standardです。ざっくりいうと以下 の条件を満たすデバイスのためのOAuthのグラントタイプです。
  1. The device is already connected to the Internet.
  2. The device is able to make outbound HTTPS requests.
  3. The device is able to display or otherwise communicate a URI and code sequence to the user.
  4. The user has a secondary device (e.g., personal computer or smartphone) from which they can process the request.
インターネットにつながっていて、HTTPSリクエストをなげることができて、ディスプレイなどURIとコードをユーザーに表示する手段をもっているデバイスということですね。これにくわえて、ユーザーがスマホやPCももっていることを前提としています。

これを満たすデバイスとしてパッと思いつくのはテレビですかね。
他に何があるのか調べてみたところAuth0のブログには例えば以下のようなものが挙げられてました。(カッコのなかは僕の補足です。)
  • 複合機(コピー機のすごいやつ)
  • フィットネストラッカ(fitbitとか?)
  • ゲームコンソール(プレステをYoutubeにつなぐとか?)
  • 冷蔵庫(これは使われ方がよくわからん。)
  • 車載インフォテインメントシステム(カーナビのことだと思われ)
  • 頭に「スマート」と付く単語なら何でも(スマートテレビとか)
個人の使い所としては(ディスプレイにはつないでいない)サーバーとして稼働させっぱなしのラズパイで、Google ドライブにつなげるとかですかね。
ただし、ユーザーコードを表示するLEDパネルなどの手段は必要です。ユーザーコードについては後述します。

シーケンス概要

シーケンス図は以下になります。

デバイスが2つ登場します。
一番右にいるのがテレビなど上記の一覧のものに対応するデバイスです。
左から二番目(Userの隣り)は要するにスマホやPCのブラウザです。
Device Authorization Grantでもリソースオーナーの認証はブラウザで行われます。

ざっくりとシーケンスを説明します。実際には任意のオプションがあったりするので
厳密なところを知りたい方はRFCをあたってください。
  • 1番でDevice Clientからリクエストします。
  • 2番でVerification URIとUser code、Devie codeが返ってきます。
  • 3番ユーザーに対してURIとUser codeを提示します。さきほど、「ラズパイにディスプレイが必要です。」といったのはここのことです。ここでユーザーにUser codeとURIを表示する必要があります。
  • 4番、5番でユーザーはブラウザを通して提示されたURIにアクセスします。
  • 6番、7番でリソースオーナとしての認証を行います。
  • 8番で認可サーバーはUser codeの入力画面を表示します。
  • 9番でUser codeを入力します。
  • 10番でデバイスから認可サーバーにトークンリクエストを行います。リクエストにはDevice codeとClientID ClientSecretが含まれます。(ClientSecretはなくていい場合もある)
図では表現できていませんが、実際には2番のリクエストが返ってきてからデバイスは認可サーバーに対して定期的にリクエストを送っています。
9番のUser codeの入力が完了すると、トークンレスポンスとしてアクセストークンが返ります。

アクセストークンをとってみよう

では、実際にアクセストークンをとってみましょう。今回はGoogle Drive APIのアクセストークンを取得します。
なお、ClientID、ClientSecret、User code、Device codeはフェイクの値をいれているので、適宜、ご自身のものに読替えてください。

まずはGoogle Cloud Platform(GCP)でクライアントを作成し、ClientID/ClientSecretを作成してください。Google Derive APIの有効かもお願いします。このあたりが参考になります。あと、こことか。

では、Googleのこちらのドキュメントにそってリクエストをなげていきます。

1番のリクエストをcurlコマンドにしたものが以下です。認可サーバーのエンドポイント"https://accounts.google.com/o/oauth2/device/code"に対してclient_idとscopeをpostで送信しています。scopeは"https://www.googleapis.com/auth/drive.file"になります。URLの形式をしているのでややこしいですが、scopeに指定する値です。Google Drive APIのscopeの情報はこちらにあります。


 SCOPE=https://www.googleapis.com/auth/drive.file
 CLIENT_ID=8337…0c2giitnggrbm.apps.googleusercontent.com
 curl -d "client_id=$CLIENT_ID&scope=$SCOPE" \
       https://accounts.google.com/o/oauth2/device/code


2番のレスポンスは以下になります。
ここでdevice_code、user_code、verification_uriがかえってきます。

 {
    "device_code": "AH-1Ng0dag4u-9n-_…YlkxO5n1xx00zD_Lpw",
    "user_code": "JFMM-LCCDSX",
    "expires_in": 1800,
    "interval": 5,
    "verification_url": "https://www.google.com/device"
  }


ここで渡されるverification_uriとuser_codeを何らかの形でユーザーに表示します。

次にユーザーの立場に立ってverification_uriである"https://www.google.com/device"にアクセスしてください。

RFCを元に記載したシーケンス図ではユーザー認証のあとUser codeの入力という順番ですが、 Googleは先にUser codeの入力を求めてきます。以下のコード入力画面がが表示されるのでuser_codeの値を入力して「次へ」を押します。



Googleのログイン画面がでるのでID/Passwordを入力してログインしてください
以下の画面が表示され、権限移譲に関する許可を確認する画面がでます。ちなみにdevice-flow-appはクライアント作成時につけたアプリの名前です。



許可ボタンをおすと以下完了画面が出ます。



では、Device Client役に戻って10番のリクエストを送信します。
なお、Googleの場合、grant_typeの値として"http://oauth.net/grant_type/device/1.0"を指定しますが、RFCではこの値は"urn:ietf:params:oauth:grant-type:device_code"となっています。


 CLIENT_SECRET=z2OUJkNDfakcasdHsng8kouse
 DEVICE_CODE=AH-1Ng0dag4u-9n-_…YlkxO5n1xx00zD_Lpw

 curl -d "client_id=$CLIENT_ID"    \
      -d "client_secret=$CLIENT_SECRET" \
      -d "code=$DEVICE_CODE"            \
      -d "grant_type=http://oauth.net/grant_type/device/1.0" \
             https://oauth2.googleapis.com/token


11番の以下のレスポンスが返ってきます。


 {
   "access_token":"ya29.Il-zB_BHbWdBm0tHfGrUAbruWVtBJSXHDVg",
   "expires_in": 3600,
   "refresh_token": "1//G4dEMfEBMKwibrEjgJEgUlFhc008",
   "scope": "https://www.googleapis.com/auth/drive.file",
   "token_type": "Bearer"
 }


access_tokenとrefresh_tokenが取得できました。アクセストークンの有効期限は3600秒ですね。

ちなみにユーザーの許可が降りる前にトークンリクエストを送信すると以下のエラーが返ってきました


 {
   "error": "authorization_pending",
   "error_description": "Precondition Failed"
 }

まとめ

Device Authorization Grantが想定しているデバイスについて概要説明とGoogleの認可サーバーから実際にアクセストークンを取得してみました。なんか間違えてたらtwitterの方にマサカリください。(震え声..)

なお、認証認可技術 Advent Calendarの明日(5日目)は@suwa-yuki さんのPKCEの記事です。

コメント