📛

OpenID Connectのlogin_hintとは何か?

2023/12/23に公開

ritouです。

Digital Identity技術勉強会 #iddance Advent Calendar 2023 シリーズ1の記事です。

https://qiita.com/advent-calendar/2023/iddance

最近はパスキーの話ばっかりしてた気がするので、たまにはOpenID Connect(OIDC)の話をしましょう。

本投稿の流れ

  • login_hint is 何?
  • GoogleのOIDCでは login_hint をサポートしている
  • 実際に使って挙動を確かめてみた

早速始めましょう。

login_hint is 何?

今日はOIDCの仕様にて定義されている login_hint パラメータを取り上げます。

OPTIONAL. Hint to the Authorization Server about the login identifier the End-User might use to log in (if necessary). This hint can be used by an RP if it first asks the End-User for their e-mail address (or other identifier) and then wants to pass that value as a hint to the discovered authorization service. It is RECOMMENDED that the hint value match the value used for discovery. This value MAY also be a phone number in the format specified for the phone_number Claim. The use of this parameter is left to the OP's discretion.

login_hint とは、ログインしようとしているユーザーの識別子についてのヒントをRPからOPに与えるのに使えるパラメータです。何やらユーザーが入力したメアドから...みたいな例が書いてありますが、この辺は置いといて良いです。重要なのは、RPからOPに送られるの認証リクエストに login_hint を含めると、OPはその値を検証して適切に処理するものである、という感じですね。言い換えると、その先はOPが考えろと言う感じです。

これだけだとイメージが沸かないかもしれませんのでちょっと対応例を紹介します。

OP側の対応例

とっても基本的なところを押さえておきましょう。

まずはOPに誰もログインしていない状態で login_hint が指定された場合を考えてみます。RPから期待されているユーザーを把握したOPは、その対象となるユーザーでログインすることを期待していているでしょう。login_hintにメールアドレスや電話番号が指定された場合、ログイン画面のユーザー識別子のフォームにメールアドレスや電話番号がフィルインされた状態になっているかもしれません。

また、login_hintにはRPがOPから受け取ったユーザー識別子(OIDCのIDTokenに含まれるsubの値)も指定できます。その場合、ユーザー識別子から参照してメールアドレスなどをフィルインしてしまうと情報漏洩云々のリスクになり得るので、何の値もフィルインされていないシンプルなログイン画面のままかもしれません。

次に、OPでログイン状態のユーザーと login_hint の値が紐づけられている場合はどうでしょうか。
その場合は期待したユーザーと一致しているので、そのまま画面表示などなしでRPに認証レスポンスを返すこともあるでしょう。

ログイン状態のユーザーと一致しなかった場合、RPが期待しているユーザーでログインさせるためにログアウトするなりして対象ユーザーでのログインに誘導させるなどが考えられます。

今回紹介したものが唯一のユースケースではなく、あくまで一例です。仕様による定義がゆるふわなので、login_hint の値をどう処理するかの設計には自由度があると言えます。

次に、実際に login_hint を利用できるGoogleの挙動を見てみましょう。

Googleの login_hint 対応

GoogleはOIDCのOPとして login_hint に対応しています。

https://developers.google.com/identity/openid-connect/openid-connect?hl=ja#login-hint

認証しようとしているユーザーをアプリが認識している場合、認証サーバーへのヒントとしてこのパラメータを提供できます。このヒントを渡すと、アカウント選択ツールが抑制され、ログイン フォームでメールアドレスが事前入力されるか、適切なセッションが選択されます(ユーザーがマルチ ログインを使用している場合)。これにより、アプリが間違ったユーザー アカウントにログインした場合に発生する問題を回避できます。 値には、メールアドレスか sub 文字列(ユーザーの Google ID 相当)を指定できます。

Googleの場合、個人のGoogleアカウントと Google Workspace を利用する会社のアカウントなど複数のアカウントでログインしている場合があります。Chromeのプロファイルを分けずに複数アカウントでログインしている状態で、単純なOIDCの認証フローを利用するとアカウント選択画面が表示されます。

ここで、login_hint に個人アカウントのメールアドレスを指定すると、対象のアカウントが個人のものに限定されます。

また、利用していないアカウントのメールアドレスを指定するとそのメールアドレスが補完されたログイン画面が表示されたり、企業のSSO管理がされている場合はそちらのIdPに遷移したりします。

では、これをRPはどう使えるのかを紹介します。

RP側のユースケース

OIDCの話だけで退屈になった方もいるでしょう。パスキーの話を少ししましょう。
パスキーのUXの中で、RPがユーザーを特定した上で認証を要求するユースケースがあります。
Identity Firstと呼ばれるパターンですね。あれはRPが対象ユーザーのパスキー一覧(厳密にはCredentialId)を指定して「これのどれかで頼む」みたいなフローですね。そこから login_hint をどう使えるかを考えてみると、次のようなものがあるでしょう。

  1. ユーザーが主張した識別子をRPがOPに送って対象ユーザーでログインさせる
  2. RPが対象ユーザーを指定して再認証を要求する

1はメールアドレスからOIDCなりSAMLなりで企業の設定したIdPに遷移していくエンタープライズのSSOのフローに似ています。

2については、コンシューマ向けID連携では再認証自体あまり使われていないのでイメージしずらいかもしれません。そういえばZennはGoogleアカウントの再認証機能がありますよね。OIDCを再認証に利用したいときに、いくつかこれがあったら便利だよなぁと思うものがあります。

  • OPに再認証をしてほしい: max_ageauth_time あたり
  • OPから受け取る認証結果に認証強度や認証コンテキストを含んでほしい: acr, amr のあたり
  • 対象ユーザーを指定させてほしい: ここで login_hint

RPが再認証を要求したいユーザーとOP上でログインしているユーザーが一致しない場合、RP側に戻ってきてその一致を検証した上でエラーを表示するなどする必要があります。このねじれみたいなのは嫌なわけですが、login_hint を使うことで改善できるかもしれません。

まとめ

  • OIDCでは login_hint というパラメータが定義されている
  • Googleはこの login_hint に対応している
  • OP側、RP側ともに良くも悪くも利用方法に自由度があるのでよく検討が必要だが、再認証のあたりでは対照ユーザーを指定するメリットがありそう。

という感じですかね。

自由度があるパラメータなので自分で設計するとなるとやや大変ですが、上手く使えると有用な仕組みかもしれません。実は、自分がソーシャルログインに対応したサービスではGoogleの login_hint パラメータを使っています。その話もどこかで書けたらいいなと思いますが、最近寒くてしんどいのでこの辺で失礼します。

ではまた。

Discussion