OpenAMでOAuth 2.0 Device Flow

## Web Viewや外部のブラウザが利用できないデバイス

スマートフォン上で動作するネイティブアプリや、ブラウザ上で動作するシングルページアプリケーションであれば、ユーザー認証・認可をすることができます。しかし、セットトップボックスや〇〇tvみたいなデバイスの多くはサインイン画面を表示できないため、こういったデバイス向けのインターフェースが必要となります。

![010.jpg](https://qiita-image-store.s3.amazonaws.com/0/148404/e2c82c3b-e973-5792-624a-336b8987f9d0.jpeg)

## OAuth 2.0 Device Flow

UIをもたないClient向けにAccess Tokenを発行するフローが**OAuth 2.0 Device Flow**です。現在はドラフトスペックですが、以下に定義されています。

* https://tools.ietf.org/html/draft-ietf-oauth-device-flow-03

たぶん、説明するより図を見た方がわかりやすいと思います。

![](http://3.bp.blogspot.com/-j9ksL1WmxOk/Vin_FfmZLFI/AAAAAAAAAoo/bAiukW_Yl4o/s1600/device_flow.png)

認証はResource Ownerが持っている別のUI（ブラウザなど）で行うんですが、Authorization Requestとの紐づけをVerification Codeで行っています。Verificationが行われるまでClientはPollingします。その後、Authorization ServerからAccess Tokenが発行されます。

## tv-player

このDevice FlowをOpenAMで試すためのClientアプリがgithub上に公開されています。

* https://github.com/smof/tv-player

## OpenAMにClient登録

いつも通り、管理者アカウント（`amadmin`）でサインインします。

**Application -> OAuth 2.0**から以下の設定をし、クライアント登録をします。

|key|value|
|:---|:---|
|client id|TVPlayer|
|client secret|Passw0rd|
|scope|givenname postaladdress description|

<img width="346" alt="002.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/dc7bde49-b050-ed04-8db6-c34e285b9c25.jpeg">

## tv-playerのセットアップ

まず、npmをインストールします

```bash
$ yum -y install npm
$ node -v
v0.10.46
```

tv-playerをgit cloneします。

```bash
$ git clone https://github.com/smof/tv-player.git
```

今回利用しているOpenAMの構成に合うように、ソースを少し修正します。

```bash
$ cd ./tv-player
$ sed -i 's/openam\(\.example\.com\)/iam\1/' routes/pair.js 
$ sed -i 's/openam\(\.example\.com\)/iam\1/' routes/pairNotification.js 
$ sed -i 's/openam\(\.example\.com\)/iam\1/' routes/favourites.js 
```

ちなみにソース上でこんな設定がされています。

```js
        //OAuth2 client details
        var CLIENTID="TVPlayer";
        var CLIENTSECRET="Passw0rd";
        var RESPONSE_TYPE="token";
        var SCOPE="description%20givenname%20postaladdress";
        //Base64 encoded OAuth2 client credentials
        var CLIENTCREDS = CLIENTID + ":" + CLIENTSECRET;
        var B64CLIENTCREDS = new Buffer(CLIENTCREDS).toString('base64');

        //Variable sent in the post request
        deviceCode=req.body.deviceCode;
        console.log("DeviceCode: " + deviceCode);


        //Create HTTP request to query OpenAM to see if authorization has taken place
        var options = {
                          host: 'iam.example.com',
                          path: '/openam/oauth2/access_token',
                          port: '8080',
                          method: 'POST',
                      headers:  {'Content-Type' : 'application/x-www-form-urlencoded'}
        };
```

tv-playerを起動します。

```bash
# node app.js
```

ポート番号`3001`にて、起動されています。

<img width="520" alt="003.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/6afd8f43-15bc-5fe7-c5c6-e4b555a91c78.jpeg">

## 動作確認する

**人っぽいアイコン**をクリックします。

<img width="520" alt="003.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/689bd6a6-f67c-d3e6-f1f4-72f2a50a16a2.jpeg">

QRコードが表示されますので、読み取ります。このコードを読み取ると、外部ブラウザが起動され、以下のURLにアクセスします。
Query StringでVerification CodeをAuthorization Serverに送信しています。

* `http://iam.example.com:8080/openam/oauth2/device/user?user_code=********`

<img width="530" alt="004.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/3acb8841-ca57-3122-b143-b2077af6af11.jpeg">

外部ブラウザ上ではOpenAMのサインイン画面が表示されますので、`johnd`でサインインします。

<img width="492" alt="005.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/c7447cd6-d5ed-852a-cca2-9be3eeb4ba54.jpeg">

先ほど送信したVerification Codeは、tv-playerから送信されたAuthorization Requestに紐づいているので、認可同意画面にもtv-playerからのclaimが表示されます。

<img width="469" alt="006.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/41308119-74b4-bfd3-a28e-f02bae8d53f0.jpeg">

同意すると、Done!!となります。

<img width="259" alt="007.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/7e9c114c-1439-69c6-6aa5-942c38d7c207.jpeg">

tv-playerの画面にもどると、ペアリングが完了しています。

<img width="362" alt="008.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/8e629c41-d560-1a61-130c-cf3a76cdd2ec.jpeg">

ホームに戻ると、tv-player上ではサインインしていませんが、access tokenの取得が出来ていますので、そのaccess tokenを使って、ユーザーIDの取得ができています。

<img width="351" alt="009][.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/148404/fa0004d1-ecac-a968-0f85-11b1ccdd6688.jpeg">

## 〆

OAuth 2.0では認証そのものの手段やフローは定義されていません。なので、Device FlowのようにOut of Band Authenticationでも問題ありません。おもしろいユースケースですね～。

あと2日か～。なにしようかな～？

ばい！