2024年1月4日木曜日

IDトークン発行のタイミングで認証済みユーザの情報をどこまで保存するか

こんにちは、富士榮です。

OpenID Providerを自前で実装する際の悩みポイントの一つが認可コード、アクセストークンをサーバ側でどの様に保存するか、という問題です。

どういうことかというと、認可コードを発行するタイミングで通常はユーザの認証を行うわけですが、そのタイミングで認証済みユーザの属性情報を取得しておいて認可コード、アクセストークンと紐づけてテーブルに保存をしておく方が実装は簡単になる一方で、最新のユーザ情報をuserInfoから取得したい場合の対応が結局必要になったり、ユーザの削除の検知のメカニズムの実装が必要になる、という話です。

ちなみに、認可コードやアクセストークンをサーバ側で一定期間保持をし続けるための実装がOpenID Providerの可用性やスケーラビリティを左右する最大のポイントの一つだと思うので、この辺りは各サービス事業者の考え方で分かれるところです。(この辺りは別ポストで詳しくお話しようと思いますが、最後までステートレスにこだわったMicrosoftは認可コードをJWTにして認証済みユーザの属性情報を暗号化して入れることでトークン要求時に認可コードからセッションをLookupしてid_tokenを生成する必要をなくしていたり、VittorioがAuthorのRFC9068/JWT Profile for OAuth 2.0 Access Tokenの様にIntrospectionエンドポイントが無くてもトークンの有効性検証ができる仕組みを実装したり、Hybrid Flowでもないのにフロントで取得できるid_tokenにはほとんど情報を入れず、userInfoやGraph APIへのアクセスをしないとユーザ属性が全く取れなかったり、、、とグローバルスケールの認証基盤を運営する上での苦労が滲み出ていたりします)

横道にそれましたが、一番簡単な実装だと認可エンドポイントへアクセスし認証されたタイミングで以下のレコードを保存しておき、


トークンエンドポイントへアクセスしアクセストークンやIDトークンを発行する際は必要なカラムを追加するなどを含めこのテーブルだけで処理がクローズできるので実装はシンプル、という話です。こんな感じです。



しかし、この実装のメリットはこのレコードだけで全ての処理が完結するため処理がシンプルになること、そしてid_token発行時とuserInfoアクセス時の間に仮にユーザの属性の更新をされても認証時点のユーザの属性情報をクライアントへ返却できる、という点があります。一方でユーザの最新の属性をuserInfoエンドポイントから返却したいケースやユーザの削除されたことを検知するメカニズムの実装が結局必要になる、など考慮点も存在します。

そのため、実際にはユーザの識別子だけをレコード状には記録しておき、トークンエンドポイントやuserInfoエンドポイントへのアクセス時は対応するユーザの属性をデータベースから取得する、という実装になるはずです。


ということで実際どういう実装になっていそうなのか確認してみます。

Microsoft Entra ID

いわゆるAzure Active Directoryです。
そもそもIDトークンに識別子以外の属性情報が入らないので自然と上記の実装になっていると考えて良いと思います。


LINE Login

こちらはid_tokenにも認証されたユーザの属性情報が入ります。

userInfoにアクセスする前にLINEアプリで名前を「開発用」から変更してみました。

この状態でuserInfoにアクセスすると、、

はい、更新後の値が取得されます。


まぁ、普通に考えたらこういう実装になるだろうな、という話でした。

0 件のコメント: