OIDCのpromptパラメータを使って認証フローを制御する
こんにちは。
OpenID Connect (OIDC) を使った認証機能は、今や多くのWebサービスやアプリで不可欠なものとなっています。しかし、単に認証できるだけではなく、「ユーザーにどのような体験を提供するか」も同様に重要です。例えば、「ユーザーに気づかれずに認証を済ませたい」「セキュリティのため、必ず再認証させたい」「どのアカウントでログインするか選ばせたい」といったニーズがあるでしょう。
OIDCのpromptパラメータは、まさにこうした認証時のユーザー体験を制御するための鍵となる仕組みです。
この記事では、OIDCのpromptパラメータが一体何であり、なぜ必要なのかを基本から解説します。そして、実際にAuth0の環境を使用してどのような挙動になるかを検証します。
promptパラメータとは
OpenID foundation の資料によると以下のような記載になっています。
prompt
OPTIONAL. Authorization Server が End-User に再認証および同意を再度要求するかどうか指定するための, スペース区切りの ASCII 文字列のリスト. 以下の値が定義されている.
prompt パラメータは、OIDCの認証リクエスト(アプリケーション=RPが認可サーバー=IdPにユーザー認証を依頼する際のリクエスト)に含めることができる、オプションのパラメータです。
その役割は、「認可サーバーに対して、認証や同意の画面(プロンプト)をどのように処理してほしいか」というヒント(指示)を伝えることです。
例えば、以下のような値を指定できます。(これらはスペース区切りで複数指定することも可能です)
-
none: 認証画面や同意画面を一切表示しないでほしい。もし表示が必要なら、エラーを返してほしい。 -
login: ユーザーが既にログイン済みであっても、強制的に認証(例:ID/パスワード入力)を要求してほしい。 -
consent: ユーザーが過去に同意済みであっても、強制的に同意画面を再表示してほしい。 -
select_account: ユーザーが複数のアカウントでログインしている場合、どのアカウントを使うか選択させてほしい。
あくまで「ヒント」であるため、認可サーバーが全ての値に常に対応するとは限りませんが、多くのOIDCプロバイダーがこれらの主要な値をサポートしています。
なぜpromptパラメータが必要なのか
もしpromptパラメータがなければ、認証時の画面表示は認可サーバーのデフォルト設定任せになってしまいます。
例えば、認可サーバーが「一度ログインしたら、できるだけ認証画面は出さない」という設定だった場合、アプリケーション側で「ここは重要な操作だから、絶対にもう一度パスワードを入力させたい」と思っても、それを強制できません。
promptパラメータが必要なのは、アプリケーション(RP)が実現したいユーザー体験やセキュリティ要件に応じて、認証フローを能動的に制御したいからです。
具体的なユースケースとしては、以下のようなものがあります。
- サイレント認証(prompt=none): ユーザーがページを訪れた際、裏側で「ログイン済みかどうか」を画面遷移なしで確認したい場合。prompt=noneを付けてリクエストを送り、成功すれば認証情報(IDトークンなど)を、失敗すれば(ログイン画面が必要などの)エラーを受け取ることで、ユーザーを邪魔せずに状態を確認できます。
- 強制再認証(prompt=login): ECサイトでの決済時や、管理者設定の変更時など、セキュリティ上特に重要な操作の直前に、「本当に本人か?」を再確認させるために使用します。
- 同意の再取得(prompt=consent): アプリケーションが要求する権限(スコープ)が変更になった際や、利用規約の更新時に、ユーザーに再度同意を求めるために使用します。
- アカウント切り替え(prompt=select_account): Googleのように複数のアカウントで同時ログインできるサービスで、アプリケーションが特定のアカウントではなく、「どのアカウントでこのアプリを使いますか?」とユーザーに選択させたい場合に使用します。
このように、promptパラメータは、OIDC認証における「かゆいところ」に手を届かせ、より柔軟で安全な認証フローを構築するために不可欠な要素なのです。
実際に検証してみる
検証環境
以前Auth0を使って爆速でOIDCの学習環境を構築するでセットアップした環境を利用します。よければご参考ください。
各パラメータの検証
以下URLにアクセスすることで検証します。
なお、prompt=select_accountの指定のみうまいこと動作しなかったので検証をスキップしています。
https://<ドメイン>/authorize?
client_id=<クライアントID>
&redirect_uri=<設定したredirect_uri>
&response_type=code
&scope=openid%20profile%20email
&prompt=<prompt>
promptの指定なし
まずはpromptを指定せずにログインしてみます。
ログイン画面が表示されるので、検証用ユーザーのサインアップをします。

すると同意画面が表示されます。
デフォルトの設定なので、profileとemailを使用することの同意を許諾する画面になっていますね。

Acceptするとクライアント側にリダイレクトされて認可コードを取得できたことが確認できました。

prompt=none
ログイン済みの場合の挙動
ログイン済みの場合は画面表示されずにログインするはずです。
Authorization Server はいかなる認証および同意 UI をも表示してはならない (MUST NOT).
実行すると想定通り、認証成功の画面が表示されました。

ログインしていない場合の挙動
ログインしていない場合はlogin_required等のエラーが返される想定です。
End-User が認証済でない場合, Client が要求する Claim 取得に十分な事前同意を取得済でない場合, またはリクエストを処理するために必要な何らかの条件を満たさない場合には, エラーが返される.
典型的なエラーコードは login_required, interaction_required であり, その他のコードは Section 3.1.2.6 で定義されている.
実行すると想定通り、login_requiredが返されました。

prompt=login
ログイン済みの状態で prompt=login を指定します。
(promptパラメータを指定せずに再実行すると、ログイン処理は不要であることを確認済みです。)
実行するとログイン画面が表示されることを確認できました。なお、同意画面は今回スキップされました。

prompt=consent
ログイン済みの状態で prompt=consent を指定します。
サインアップ後は明示的に指定しなければ特に同意は要求されませんが、パラメータを指定すると同意画面を表示できることが確認できました。

まとめ
本記事では、OIDCのpromptパラメータの基本的な役割から、実際の検証を通じた具体的な動作までを解説しました。
promptパラメータは、単なる「オプション」ではなく、アプリケーション(RP)がユーザー認証体験(UX)とセキュリティレベルを能動的に制御するための重要な鍵であることをご理解いただけたかと思います。
パラメータを使いこなせるかどうかは、認可サーバー(IdP)のデフォルト動作の「言いなり」になるのではなく、RP側が認証フローの主導権を握れるかどうかに直結します。
セキュリティが重要な操作の前にprompt=loginで再認証を挟む、あるいはprompt=noneでユーザー体験を損なわずにログイン状態をチェックするなど、適切な場面で適切な値を指定することが、堅牢で使いやすいサービスの構築につながります。
OIDCを「ただ導入する」だけでなく、promptパラメータのような詳細な仕様を理解し、検証することで、より質の高い認証実装が可能になります。本記事の検証結果が、皆さんの実装の一助となれば幸いです。
Discussion