OAuth2.0 Clientでの各種トークン管理について調べてみた (Web App)

はじめに

 これはポエムです。
 mod_auth_openidcの実装からClientでの各種トークンの管理について調べて学びを得ます。

github.com

 対象としてmod_auth_openidcを選んだ理由については、既存のアプリケーションの実装に依存せずに諸々を良い感じに処理してくれる印象があったからです。
 また、設定が豊富で様々な方法を提示されており、トークン管理について調べる題材として良いと思ったからです。  今回はConfidential Clientでの話になります。Public Clientではまたトークンの保管方法は違うはずなのでご了承ください。

動作確認

 動作環境については以下のリポジトリに用意してあります。 github.com

 ここでは上記の動作確認方法について説明をしておきます。特に動作確認する必要が無ければ読み飛ばしてください。
 まず、/ets/hosts/に以下のように追記しておきます。

127.0.0.1    localhost keycloak

 次にリポジトリをクローンして諸々を立ち上げます。

$ git clone https://github.com/kg0r0/keycloak-oidc-compose.git
$ cd keycloak-oidc-compose
$ docker-compose build
$ docker-compose up -d

 諸々立ち上がったら、http://localhost/privateにブラウザからアクセスします。
 すると、ログイン画面が表示されるのでUsernameにuser、Passwordにpasswordをそれぞれ入力します。 f:id:kent056-n:20190701093316p:plain  正しく入力できるとログインが成功し、アプリケーションにヘッダの情報が表示されます。
f:id:kent056-n:20190701093344p:plain

 今回のサンプルアプリケーションでは何が起きているか把握するためにアプリケーションでAccess Tokenなどを表示しています。
 本来Access TokenはClientが保持する秘密の値であるため、今回のようにアプリケーションで表示しないでください。

トークンの管理について

 mod_auth_openidcで各トークンがどのように扱われるのか調べます。
 最初に各トークンの扱いを調べる前にmod_auth_openidcが管理する情報を確認しておきます。
 mod_auth_openidcは以下の情報をキャッシュするようです。

  • authenticated user session state
  • nonce values from authorization requests (to prevent replay attacks)
  • validated OAuth 2.0 access tokens
  • JWK sets that have been retrieved from jwk_uri's (to validate ID tokens)
  • resolved OP metadata when using OIDCProviderMetadataUrl
  • JWT ID claims (jti) when using OP-init-SSO draft-bradley-oauth-jwt-encoded-state
  • temporary state associated with Request URI's

 また、キャッシュ先としては以下の中から選ぶことができるようです。

  • shared memory (default)
  • memcache
  • Redis
  • file storage

https://github.com/zmartzone/mod_auth_openidc/wiki/Caching

ID Token

 ID Tokenを検証して、Cookieをセットするまでの処理はmod_auth_openidcがおこなっており、基本的にアプリケーションがID Tokenを直接扱う必要はなさそうです(Hybrid Flowの時は要確認)。
 アプリケーション側から見てID Tokenが隠蔽されていた場合、認証後にユーザー情報を取得してページを表示したい場合に不便にならないかという懸念がありますが、それは問題なさそうです。
 先ほどの動作確認結果からOIDC_CLAIMというヘッダでID Tokenの情報がアプリケーションに渡ってきているのが確認できます。
 また、後述しますがOIDC_access_tokenヘッダでAccess Tokenもアプリケーションに渡されており、User Infoエンドポイントを叩くことも可能です。
 モジュール自身がUser Infoエンドポイントを叩いてextra claimsについても解決してくれるようなことも記載されています。

The access_token that mod_auth_openidc receives from the OP will be used by the module itself against the user_info endpoint of the OP (if configured) to resolve extra claims about the user. Besides that an application may be interested in the access_token to use it against other OAuth 2.0 protected APIs, typically when additional scopes have been requested in addition to the OpenID Connect scopes (using OIDCScope).

 検証時に認証および認可もする場合、以下の2つの方法が用意されています。

  • Use the functions that mod_auth_openidc provides to authorize users based on the claims that have been provided for that user by the OpenID Connect provider.

  • Use another Apache module that performs the authorization based on the user identity provided by mod_auth_openidc.

https://github.com/zmartzone/mod_auth_openidc/wiki/Authorization

 認証後はCookieがセットされることが記載されています。mod_auth_openidcではID Tokenの管理というよりもユーザーのセッション管理をおこなっているようです。

The "session" cookie is created after the user returns from the OpenID Connect provider with a successful authentication response (note that the state cookie is deleted at the same time).

https://github.com/zmartzone/mod_auth_openidc/wiki/Cookies#session-cookie

 実際にCookieがセットされていることが確認できます。 f:id:kent056-n:20190701110638p:plain

Access Token

 先程確認したキャッシュの項目にvalidated OAuth 2.0 access tokensがあるので、Access Tokenの管理もmod_auth_openidcがやってくれてそうです。  mod_auth_openidcではAccess TokenはOIDC_access_tokenというヘッダでアプリケーションに渡されるようです。

For that purpose mod_auth_openidc passes the access_token that it receives from the OP to applications in a header named OIDC_access_token.
https://github.com/zmartzone/mod_auth_openidc/wiki/Access-Tokens-and-Refresh-Tokens

 リバースプロキシからアプリケーションへのリクエストに毎回Access Tokenがヘッダにセットされてくるので、要件にもよりますがアプリケーションでAccess Tokenを管理する必要はあまりなさそうです。

Refresh Token

 Refresh Tokenはmod_auth_openidcがユーザーセッションに紐づけて管理してくれるようです。

If a refresh_token is returned by the OP, the module stores the refresh_token in the user session.

 また、Refresh TokenによるAccess Tokenの更新もmod_auth_openidcが担ってくれるようです。

When called on this hook mod_auth_openidc will refresh the access_token using the stored refresh_token as described in the OpenID Connect specification in section 12. Using Refresh Tokens.

https://github.com/zmartzone/mod_auth_openidc/wiki/Access-Tokens-and-Refresh-Tokens

まとめ

今回はリバースプロキシの構成でトークンの管理について見てみました。
どういった認証モジュールを利用するかにもよりますが、今回利用したmod_auth_openidcだとアプリケーション側でトークンを管理する手間はかなり少なそうです。
他の認証モジュールを利用する場合だと、一部担っていない機能などあると思うのでそこは自前で管理する必要がありそうです。
所感としては、アプリケーション側からトークンの検証や管理を隠蔽しつつ、必要な情報はちゃんとアプリケーションに渡しているんだなあという感じです。