ユースケース — マルチアカウント選択
prompt=select_account とは
OIDC Core 1.0 §3.1.2.1 では、RP が /auth に prompt 要求パラメータを付けられます。このページに関係するのは次の 3 つの値です。
prompt= | OP に依頼する内容 |
|---|---|
none | UI を出さない。既存のセッションで応答するか、失敗する |
login | 有効なセッションがあっても、再ログインを強制する |
select_account | アカウント選択 UI を表示し、ユーザが続行するアカウントを選ぶ |
select_account は、大手 SaaS の「アカウント切り替え」ボタンが送る値です。1 つのブラウザで、同じ OP に複数のアカウント(仕事用と個人用、alice と bob など)でサインインしているとき、OP が一覧を出してユーザに選ばせます。chooser が出るのは、ブラウザにすでに有効なセッションがある場合だけで、なければリクエストはそのままログインに進みます。
ライブラリはこれを chooser group として実装しています。1 つのブラウザがサインインしているセッションの集まりを OP のセッションマネージャが保持し、アカウントの追加、有効なセッションの切り替え、全体のサインアウトを行います。
RP-Initiated Logout はこの group を対象にします。logout_scope なしの /end_session は、chooser group のすべてのセッションを破棄します。logout_scope=current(受け付ける値はこれだけで、1 回だけ指定します)は有効なセッションだけを破棄し、cookie を残ったセッションに向け直します。空値、未知の値、重複した logout_scope は HTTP 400 になり、group は変更されません。セッションと一致しない id_token_hint では、ユーザの確認が必要で、確認を省略することはできません。一致する hint で確認を省略できるのは、そのアカウントだけが終了する場合です。同じブラウザにサインインしている他のアカウントも一緒に終了する場合は、OP がユーザに確認を求めます。
このページで触れる仕様
- OpenID Connect Core 1.0 — §3.1.2.1(
promptパラメータ)、§3.1.2.4(同意との相互作用) - OpenID Connect Back-Channel Logout 1.0 — 「全員ログアウト」が発火したときの一斉通知
用語の補足
promptパラメータ: RP が/authに付けて、OP に UI の出し方を伝えるヒントです。none(UI を出さず、既存のセッションで応答するか失敗する)、login(再ログインを強制)、consent(同意画面を強制)、select_account(アカウント選択 UI)の 4 種類があり、スペース区切りで複数指定できます。- chooser group: 同じブラウザで同時にサインインしているセッションの集まりです。大手 SaaS の「アカウント切り替え」メニューに当たります。OP がサーバ側で group を保持し、cookie はブラウザを個々のセッションではなく group に結び付けます。
sub(subject): OP と RP の組ごとに決まる、ユーザの安定した不透明な識別子です。chooser でアカウントを切り替えると、次のid_tokenのsubが変わります。同じブラウザで、別の ID になります。
ソース:
examples/13-multi-accountは JSON ドライバで chooser を扱う例、examples/12-custom-chooser-uiは HTML テンプレート差し替え経路の例です。
動作
prompt=login ではありません。それでは現在のアカウントが置き換わってしまいます。chooser が渡す「アカウント追加」リンクを使い、その内部マーカーで、cookie が指す group に加わるよう OP に伝えます。実装
prompt=select_account 用の interaction は組み込みです。有効な chooser group の全アカウントと AddAccountURL を並べた interaction.ChooserPromptData を返します。既定の HTML ドライバでは、同梱のテンプレートが一覧を描画し、ユーザは選んだ SessionID を POST で送り返します。サーバ描画の流れを保ったままテンプレートだけを自前にしたいときは、op.WithUI(op.HTMLUI{Chooser: op.PageTemplate{Template: tmpl}}) を渡します。
JSON ドライバ(op.WithUI(op.DriverUI{Driver: interaction.JSONDriver{}}))では、SPA が同じデータを JSON で受け取り、SessionID を POST で送り返します。op.SPAUI を使う場合も、chooser は同じように SPA が受け持ちます。
アカウントを追加するには、手で組み立てた URL ではなく、prompt の AddAccountURL を使います。元の /auth リクエストに prompt=login と chooser group を示す内部マーカーを付けたもので、OP は、ブラウザがその group の cookie をまだ持っている間だけマーカーを有効にします。素の prompt=login は現在のアカウントを置き換えます。RequirePAR(たとえば FAPI 2.0)の配備では、クエリ文字列の /auth URL は拒否されるため、OP は AddAccountURL を空にします。その場合は「アカウント追加」リンクを隠してください。
セッションマネージャは内部の型で、アプリケーションコードから呼び出すことはありません。/auth と chooser interaction を処理する中で、OP が次の 4 つの操作を行います。
| 操作 | タイミング |
|---|---|
| 新しい chooser group を開く | そのブラウザでの最初のログイン |
| group にアカウントを追加する | AddAccountURL から始めたサインイン |
| 有効なセッションを切り替える | chooser でユーザがアカウントを選んだとき |
| group 全体を終了する | 全員のサインアウト(logout_scope なしの /end_session) |
組み込み側が実装するセッション用の interface は store.SessionStore(Save、Find、Touch、Delete、ListByChooserGroup)だけで、自前のセッションバックエンドを使う場合にだけ必要です。
選択の後も、通常のリクエスト検査は適用されます。選ばれたセッションが、リクエストの max_age に対して古い、acr_values を満たさない、またはリクエストに prompt=login が付いている場合は、リクエストを失敗させず、そのアカウントに再認証を求めます。選ばれたアカウントは、戻ってきたセッションと同様に、LoginFlow のルール、Decider、リスクに応じたステップアップも通ります。再認証になった選択では、選ばれたセッションが新しい auth_time、acr、amr でローテーションされます。
続きはこちら
- カスタムアカウント選択 UI — chooser をサーバ描画のまま保ち、アカウント選択テンプレートだけ差し替える。
- SPA / 対話画面のカスタマイズ — アカウント選択を SPA から扱う。
- バックチャネルログアウト — 全員ログアウト時の一斉通知。