GoogleのOpenID Connectorを使ってみた

GoogleのOpenID Connectorを使ってみた

OpenID Connector の勉強のために Google の OpenID Connector を使ってみたのでメモ。
(後述するように OAuth2.0 を使ってみたという方が正しいかもしれませんが)

# 参考

以下の記事で Yahoo! JAPAN での例があり、まずはこちらをやってみてそれから Google でもやってみました。

[OpenID Connect体験](http://qiita.com/sonedazaurus/items/753a65186f1be7185b39)

また、以下についてもとても参考になりました。

[オッス！オラ認証周りをまとめてみた](http://mnakajima18.hatenablog.com/entry/2016/05/04/205713)


# やってみる

基本的なやり方は以下の Google のサイトに全部書いてあります。

[OpenID Connect ](https://developers.google.com/identity/protocols/OpenIDConnect)

なお、上記にも書いてありますが、基本的にはこれらの処理はライブラリを使ってやった方が良いかと思いますが、今回は処理の流れを理解するためにCLIやリクエストのURLを組み立てながら理解を深めます。

なお、トークン生成及びトークン確認部分はスキップしました。
必要な方はドキュメントを読んでご確認下さい。

+ [1.Create an anti-forgery state token](https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken)
+ [3.Confirm the anti-forgery state token](https://developers.google.com/identity/protocols/OpenIDConnect#confirmxsrftoken)

また **やってみること** を目的としてそれぞれの詳細については書いてないので必要に応じてドキュメントなどを参照下さい。(というか勉強不足)

## Setting up OAuth 2.0

[Setting up OAuth 2.0](https://developers.google.com/identity/protocols/OpenIDConnect#appsetup)

まずはクライアントOAuth2.0の設定を行って、クライアントID、クライアントシークレットを作成します。

え、Auth2.0？と思ったのですが、Google OAuth2.0は認証・認可の両方で使用でき、OpenID Connecotorの仕様に準拠しているとの事でこちらで問題ないかと思います。

[OpenID Connect ](https://developers.google.com/identity/protocols/OpenIDConnect)

>Google's OAuth 2.0 APIs can be used for both authentication and authorization. This document describes our OAuth 2.0 implementation for authentication, which conforms to the OpenID Connect specification, and is OpenID Certified


では、設定をしてみます。

+ Credentils ページへGo
+ 「認証情報を作成」->「OAuthクライアントIDを選択」
+ 「アプリケーションの種類」では「ウェブ アプリケーション」を選択。「承認済みの JavaScript 生成元」と「承認済みのリダイレクト URI」については「http://example.com」を指定

これでクライアントID、クライアントシークレットを取得できるかとお思います。

## Send an authentication request to Google

[2. Send an authentication request to Google](https://developers.google.com/identity/protocols/OpenIDConnect#sendauthrequest)

認証リクエストを Google に送信します。
リクエスト例は以下に記載してあります。

```
https://accounts.google.com/o/oauth2/v2/auth?
 client_id=424911365001.apps.googleusercontent.com&
 response_type=code&
 scope=openid%20email&
 redirect_uri=https://oauth2-login-demo.example.com/code&
state=security_token%3D138r5719ru3e1%26url%3Dhttps://oauth2-login-demo.example.com/myHome&
 login_hint=jsmith@example.com&
 openid.realm=example.com&
 hd=example.com
```

今回は必須パラメーターのみ指定します。

`clinet_id`パラメーターは先程取得したクライアントIDを指定します。
`redirect_uri`パラメーターは先程設定を行った「http://example.com」とします。
`scope`及び`state`パラメーターは例と同じにします。

以下のような感じです。

```bash
https://accounts.google.com/o/oauth2/v2/auth?
client_id={client_id}&
response_type=code&
scope=openid%20email&
state=security_token%3D138r5719ru3e1%26url%3Dhttps://oauth2-login-demo.example.com/myHome&
redirect_uri=http://example.com/
```

これをブラウザで実行します。
すると Google のログインを要求する画面が表示されると思うのでログインします。
その後、リダイレクトURLに指定したURLに幾つかのクエリストリングが付与された形でリダイレクトされます。

例:

```
http://example.com/?state=security_token%3D138r5719ru3e1%26url%3Dhttps://oauth2-login-demo.example.com/myHome&code={code}&authuser=0&session_state=3905e07b81a3d9a929f5f17cc8b75a18af03a039..04b6&prompt=none#
```

`state`はリクエスト時に指定したパラメーターと同じ値が指定されています。
`code`パラメーターは one-time authorization code であり、以降の処理では`code`パラメーターを使います。

## 4. Exchange code for access token and ID token

[4. Exchange code for access token and ID token](https://developers.google.com/identity/protocols/OpenIDConnect#exchangecode)

`code`パラメーターを使ってアクセストークン、IDトークンを取得します。
今度は GET ではなく POSTです。
ドキュメントにあるリクエスト例は以下。

```
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.example.com/code&
grant_type=authorization_code
```

`code`パラメーターは先程取得した値を指定します。
`clinet_id`パラメーターは最初に取得したクライアントIDを指定します。
`client_secret`パラメーターは最初に取得したクライアントシークレットを指定します。
`grant_type`パラメーターは「authorization_code」を指定します。

今回は`curl`コマンドでリクエストしてみます。

```bash
$curl -H 'Content-Type:application/x-www-form-urlencoded' \
-d "code={code}&client_id={client_id}&client_secret={clinet_secret}&redirect_uri=http://example.com/&grant_type=authorization_code" \
https://www.googleapis.com/oauth2/v4/token
```

成功すれば以下のJSON形式のレスポンスが取得できます。

```
{
 "access_token": "xxx",
 "token_type": "Bearer",
 "expires_in": 3437,
 "id_token": "xxxx"
}
```

なお、再度同じキーを使って見ると以下のようにエラーとなります。

```
{
 "error": "invalid_grant",
 "error_description": "Code was already redeemed."
}
```

また、パラメーターが不正の場合には上記のようにエラーの詳細が返却されるので確認してパラメーターを修正して下さい。


## 5. Obtain user information from the ID token

[5. Obtain user information from the ID token](https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo)

ドキュメントにも書いてあるように取得した id_token はJWT (JSON Web Token)となります。

ライブラリなどでデコード出来るようですが、今回は以下のサイトにコピペしてデコードしてみます。

[JWT](https://jwt.io/)

JWTは「ヘッダー部」、「ペイロード部」、「シグネチャー部」と別れている事が確認出来ます。
また、ペイロード部には様々な情報が記載されており、例えばEmailアドレスが確認できます。

それぞれのフィールド(claim)については [5. Obtain user information from the ID token](https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo) に記載がありましたのでこちらを参照下さい。

その他JWTの詳細は別サイトなどで確認頂いた方が良さそうです。

+ [JWTについて簡単にまとめてみた](https://hiyosi.tumblr.com/post/70073770678/jwt%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E7%B0%A1%E5%8D%98%E3%81%AB%E3%81%BE%E3%81%A8%E3%82%81%E3%81%A6%E3%81%BF%E3%81%9F)
+ [JSON Web Token の効用](http://qiita.com/kaiinui/items/21ec7cc8a1130a1a103a)