OAuth 2.0 / OpenID Connect (OIDC) でアクセストークンを検証する方法
はじめに
OAuth 2.0 と OpenID Connect について読んでいて、実装していたらよくわからなくなったのでいろいろ調べてみた。
RFC 6749 - The OAuth 2.0 Authorization Framework, Section 1.2 のダイアグラムを用いて説明すると、この図において (E) と (F) の間に、Resource Server が受け取ったアクセストークンを、① Authorization Server が発行した ② 有効であるトークンであること を確認して、かつ ③ クライアントが誰なのか を特定する方法を知りたい。
調べてみたら、その中でも、Authorization Server に依存する方法と、Authorization Server に依存しない方法がある。
特定の Authorization Server に依存する方法
Resource server は、サポートされている IdP を全て知っているので、それぞれの IdP から発行された access token の扱い方がわかるはずである。例えば、
- Google の access token は、https://oauth2.googleapis.com/tokeninfo を利用してその有効時間、およびその access token のユーザーの email を調べることができる
- Authorization server が発行する access token が JWT であれば、Authorization Server でそれを生成するための公開鍵を予め取得して、JWT が確実にその鍵で生成されていることを確認したら JWT の内容から
exp
やメールアドレスなどの情報を取り出せるはずである。実際ペイロードのフォーマットは authorization server によって違う可能性がある。
どの Authorization Server でも使える方法
かなり気になるのは、どの authorization server でも使える方法があるのかを知りたかった。なぜならば、もしそれがあれば、resource server を実装するときどの authorization server が使われているのか気にする必要がなく、あとで簡単に変えられる。実際二つの方法があるが、利用するためには authorization server がそれをサポートしている必要がある。
OAuth 2.0 Token Introspection (RFC7662) を利用する
Authorization server が OAuth 2.0 Token Introspection (RFC7662) をサポートしている場合、access token を introspection endpoint に送ることでトークンの有効期限などを取得することができる。以下は RFC7662 Section 2.2 で与えられたリクエストとレスポンスの例である。
POST /introspect HTTP/1.1
Host: server.example.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
token=mF_9.B5f-4.1JqM&token_type_hint=access_token
HTTP/1.1 200 OK
Content-Type: application/json
{
"active": true,
"client_id": "l238j323ds-23ij4",
"username": "jdoe",
"scope": "read write dolphin",
"sub": "Z5O3upPC88QrAjx00dis",
"aud": "https://protected.example.net/resource",
"iss": "https://server.example.com/",
"exp": 1419356238,
"iat": 1419350238,
"extension_field": "twenty-seven"
}
OpenID Connect の UserInfo Endpoint を利用する
本記事では、UserInfo Endpoint を利用する方法について説明したが、このコメントで説明した理由で不適切である。
Authorization server が OAuth2 だけではなく、OpenID Connect もサポートしている場合、access token を UserInfo Endpoint に送ることで、ユーザー情報を取得することができる。その上に、有効な access token でなければエラーになるので、有効かどうかのチェックもできる。
まとめ
- Authorization server によって access token を検証する方法が違う
- どの authorization server でも検証できる方法は、
OpenID Connect の UserInfoEndpoint とOAuth 2.0 Token Introspection があるが、authorization server がそれをサポートしている必要がある
Discussion
アクセストークンの有効無効の判定、必要とするクライアントやユーザーの情報取得が "できること" と "していいこと" は別です。
OpenID ConnectのUserInfo Endpointは通常のResource ServerのEndpointです。
ここにアクセスできる立場はAuthorization Serverからアクセス権限を得た "Client" であり、Clientからリソースアクセスを受けた(別の)Resource Serverではありません。
Authorization ServerとResource Serverの関係は一般的にあまり意識されない部分ですが、Resource ServerはClientやResource Owner/End Userの情報全てにアクセスできる存在とは限りません。場合によってはClientよりもアクセス許可されている情報の範囲が狭い可能性もあり得ます。
例えばClientにはEndUserの住所情報へのアクセスが許可されているがResource Serverには許可されていないケースを想定してください。Resource Serverは受け取ったアクセストークンをUserInfo Endpointに投げることで本来許可されていない情報を扱う/扱える状態になります。これは意図せぬ情報漏洩、権限昇格を招く恐れがあるので、基本的にしてはいけないことと捉えるべきでしょう。
introspection endpointの方はこの用途のために定義されたエンドポイントなので問題はありません。
上記のようなアクセス権限に細かい制限がある場合、アクセス元のResource Serverであることを認証する必要も出てくるでしょうしResource Serverに対して許可されている範囲の情報だけが返されます。
本投稿の内容においては、
この2点を認識されると良いと思います。
ご指摘いただきありがとうございました。
記事を修正し、このコメントへのリンクを追加しましたので、ご確認いただけると幸いです。