初めに・この記事の概要
記事をご覧いただきありがとうございます。
本記事では、認証・認可に関連する OpenID Connect(OIDC) の流れや認可コードフローについて、実際のリクエスト単位で整理します。自身が初学者として学習を進める中でなかなかイメージをつかみづらかったこともあり、具体的な通信内容・画面例を交えながら紹介してみたいと思います。
想定読者
私自身が初学者であることからも、本記事は以下のような読者の方を想定しています。
- 認証技術について学び始めた方
- OIDC認可コードフローの具体的な処理の流れを実際に目で見て確認したい方
OpenID Connect (OIDC)の概要
OIDCとは
OpenID Connect(OIDC)は、OAuth 2.0 を拡張した認証連携のためのプロトコルです。
「認証」とは、そのユーザーアカウントへのアクセスが、そのユーザーアカウントを持つ正しい相手からのアクセスかどうかを検証し、その結果を返却することです(当人認証)。
「認証連携」とはあるユーザーが認証されたという情報を、他のサービスやシステムに伝達することで、それを安全にやり取りする方法を標準化したものの一つに、OIDCがあります(他にも、SAMLなどがあります)。
認可コードフロー
OIDCのフローにはいくつか種類がありますが、本記事では、特にセキュアである認可コードフローをテーマにその流れをブラウザから見てみたいと思います。認可コードフローは、クライアントID・クライアントシークレットという情報を安全に保存することができるアプリケーションに適したフローです。
認可コードフローの流れ
以下は登場人物とOIDCにおける用語の対応と、認可コードフローの流れを示すシーケンス図です。
登場人物とOIDCにおける用語の対応
| 登場人物 | OIDCでの用語 |
|---|---|
| ユーザー (ブラウザ) |
User Agent (End-User) |
| 認証サーバー | OpenID Provider(OP) |
| アプリケーション | Relying Party(RP) |
※OIDCの仕様ではUser Agent(End-User)ですが、本記事ではユーザー(ブラウザ)と表記します
シーケンス図
環境構築
本記事では、こちらの書籍に従った認証連携を実装しており、RPとしてSpring Bootによるクライアントアプリ、OPとしてKeycloakを使用します。
詳細な実装内容は6.2節Spring Securityを用いた認証連携に記載されています。
認証と認可 Keycloak入門 第2版 OAuth/OpenID Connectに準拠したAPI認可とシングルサインオンの実現(リックテレコム)
中村雄一、和田広之、田村広平、田畑義之、青柳隆、渡辺竜二、奥浦航、相田洋志 著
https://www.ric.co.jp/book/development/detail/2081
クライアントアプリをKeycloakと連携した際の構成は下記の構成図のようになります。
Keycloakの構築
動作環境
- Keycloakバージョン:26.3.3
- Javaランタイム:OpenJDK 21.0.8
- デプロイ環境:Windows Subsystem for Linux 2 (WSL2)
(本検証では ローカルホストのWSL2上でKeycloakを動作させています)
Keycloakの設定
設定項目、設定値は以下です。
| 設定項目 | 概要 | 設定値 |
|---|---|---|
| Client type | 認証プロトコルをプルダウンで選択。 | OpenID Connect |
| Client ID | クライアントを識別するためのID。 | springboot-oidc |
| Client authentication | クライアントタイプを選択するボタン。Onだとコンフィデンシャルクライアント、Offだとパブリッククライアントとなる。 |
On |
| Valid redirect URIs | 認証レスポンスでリダイレクト可能なURL。 | http://localhost:8180/login/oauth2/code/keycloak |
| Valid post logout redirect URIs | ログアウト後にリダイレクト可能なURL。 | http://localhost:8180/user-area |
-
ユーザー設定
OP(Keycloak)との認証連携後、ログインを実行するためのユーザーを管理コンソール画面のUsers>Add userから作成します。
設定項目、設定値は以下です。
| 設定項目 | 概要 | 設定値 |
|---|---|---|
| Username | ユーザー名 | user001 |
| ユーザーのメールアドレス | user001@example.com |
|
| First name | 名 | user |
| Last name | 姓 | 001 |
クライアントアプリの構築
動作環境
- デプロイ環境:WSL2(Keycloakサーバーと同一のWSL2上で動作)
利用アプリ
下記のGitHubリポジトリをクローンし、ソースのビルド、およびSpring Bootアプリケーションを起動しています。
https://github.com/keycloak-book-jp/keycloak-book-jp-v2/tree/main/06-02/sso/springboot-oidc
今回はサーバー間通信を見るため、ログの出力設定に変更を加えています。
具体的には、クライアントアプリのapplication.propertiesファイルに以下を追記しました。
# アプリケーションのログをファイルに出力する設定
logging.file.name=myapp.log
# Spring Securityの全般的なログレベルをTRACEに設定
logging.level.org.springframework.security=TRACE
# OAuth2クライアント関連のログレベルをTRACEに設定
logging.level.org.springframework.security.oauth2=TRACE
認可コードフローの流れをリクエスト単位でみよう!
使用したブラウザ
- Microsoft Edge for Business
- バージョン 139.0.3405.111 (公式ビルド) (64 ビット)
開発者ツールによるリクエストの確認方法
ブラウザ(ユーザー)とサーバー間のリクエストを見るために開発者ツール(F12キーまたはCtrl+Shift+I)を開き、Networkタブを表示します。
開発者ツールを表示した状態でWebページにアクセスすると、そのページを表示するまでに生じたリクエストのリストが1行1リクエストの単位で表示されます。リクエストは上から下に時系列順で表示されます。
このツールを使って認可コードフローの各手順に該当するリクエストを探し、詳細を見ていきたいと思います。
【ユーザー操作手順1】認証連携設定済みのRP(クライアントアプリ)にアクセス
まずブラウザを起動します。そして、アドレスバーにアクセスしたいRP(クライアントアプリ)上のURL(http://localhost:8180/user-area)を入力し、Enterを押します。
認可コードフローを参照すると、以下のようなやり取りがブラウザ・RP
(クライアントアプリ)・OP(Keycloak)間で行われていることが分かります。
それでは、まず、ログイン画面を表示するに至るまでのやり取りを認可コードフローの手順に沿ってリクエスト単位で追ってみましょう。
1.Webアプリケーションにアクセス
まず、1番上に位置する、最初に生じるhttp://localhost:8180/user-areaへのリクエストの詳細を確認します。

リクエストを選択すると、3つのタブがあり、それぞれ以下の情報が載っています。

| タブ表示名 | 概要 |
|---|---|
| General | 選択したHTTPリクエストの「基本情報・全体の概要」が表示される。 |
| Response Headers | サーバーが返した「HTTPレスポンスヘッダー」が表示される。 |
| Request Headers | ブラウザがサーバーに送った「HTTPリクエストヘッダー」が表示される。 |
このリクエストについてGeneralタブと、その応答であるResponse Headersの詳細を確認します。
ここから、http://localhost:8180/user-areaのレスポンスにLocationヘッダーが設定されており、http://localhost:8180/oauth2/authorization/keycloakへリダイレクトが生じていることがわかります。
今回使用しているRP(クライアントアプリ)の仕様上URLアクセス後、http://localhost:8180/oauth2/authorization/keycloakにリダイレクトして認可コードフローを開始します。
指定されたリダイレクト先(http://localhost:8180/oauth2/authorization/keycloak)へのリクエスト詳細を、Generalタブと、Response Headersタブから確認します。

すると、今回もリダイレクトが発生しており、リダイレクト先はOP(Keycloak)の認可エンドポイント(http://localhost:8080/realms/demo/protocol/openid-connect/auth)が指定されています。
このリダイレクトが、認可コードフローでの「2.認証リクエストを送信」に該当します。
2.認証リクエストを送信
http://localhost:8180/oauth2/authorization/keycloakへアクセスし、発生したリダイレクトを受けて、次に発生するhttp://localhost:8080/realms/demo/protocol/openid-connect/authへのリクエストが、「2.認証リクエストを送信」に該当します。

ここで、Request URLをよく見てみると、URLの後ろにクエリパラメータがいくつか設定されていることがわかります。
まず、見やすいように改行しました。
http://localhost:8080/realms/demo/protocol/openid-connect/auth?
response_type=code&
client_id=springboot-oidc&
scope=openid&
state=mn_LzkEAIxmnFJm_Go7zqzfb2h8zZZYOHCcv0BbUst4%3D&
redirect_uri=http://localhost:8180/login/oauth2/code/keycloak&
nonce=R1K2pqgZTrRGxHsMPPc4OiogWyDV2JvNzYNh8b-J9fU
認可エンドポイントのURLには、全部で5つのクエリパラメータが設定されていました。
| パラメータ名 | 概要 | 値 |
|---|---|---|
| response_type | 認証フローの種類を指定します。 認可コードフローの場合は codeを指定します。 |
code |
| client_id | OP(Keycloak)に登録済のクライアントの識別子。 OP(Keycloak)の管理コンソールから設定することができます。 |
springboot-oidc |
| scope | アクセストークンに関連付けたいスコープ。OIDCの場合、認証リクエスト時にopenidをセットすることが必須。 |
openid |
| state | クライアントが生成した一意の文字列。 セッションと関連付けて保持することでCSRF対策などに利用される値。 |
mn_LzkEAIxmnFJm_Go7zqzfb2h8zZZYOHCcv0BbUst4%3D |
| redirect_uri | OIDCのリダイレクトURI。Spring SecurityのOAuth 2.0 Loginを利用してRPをOIDCに対応させる場合、/login/oauth2/code/[プロバイダー名]という形式となる 。 |
http://localhost:8180/login/oauth2/code/keycloak |
| nonce | クライアントが生成した一意の文字列。 セッションと関連付けて保持することでリプレイ攻撃対策などに利用される。 |
R1K2pqgZTrRGxHsMPPc4OiogWyDV2JvNzYNh8b-J9fU |
3.ログイン画面の表示
OP(Keycloak)はブラウザからの認証リクエストを受け取ると、ユーザーが未認証の場合ログイン画面を返却します。
ということは、先ほどのhttp://localhost:8080/realms/demo/protocol/openid-connect/authからのレスポンスが「3.ログイン画面の表示」にあたります。
【ユーザー操作手順2】 Username/Passwordを入力しSign Inをクリックし、ログイン
表示されたログイン画面で、今回のデモ用に作成したユーザー情報を入力し、Sign Inをクリックします。

すると、もともとアクセスを試みていたhttp://localhost:8180/user-areaのページが表示されました。

認可コードフローの視点から見ると、ログイン操作を実行し、認証が完了して画面が表示されるまでは以下のようなやり取りが発生しているはずです。
引き続き、認可コードフローの手順に沿って、RP(クライアントアプリ)のリソースが表示されるまでの通信内容を追ってみましょう。
4.ログイン操作
ログイン画面でテスト用ユーザーIDとパスワードを入力し、ログイン操作を実行します。
この時、最初に送信されるhttp://localhost:8080/realms/demo/login-actions/authenticateへのリクエストについて詳細を確認します。
Request MethodがPOSTになっており、フォームに入力したユーザー情報がPOSTメソッドで送信されていることがわかります。
今回の設定では、このリクエストを送信するエンドポイントにおいて、KeycloakがユーザーID・PWを使った認証処理を行っています。認証処理については、OIDCの仕様範囲外です。そのため、設定されているパラメータはKeycloak独自に設定されたものとなります。各パラメータの概要については下記のとおりです。
| パラメータ名 | 概要 | 値 |
|---|---|---|
| session_code | 認証セッションを示す一意なコード。OP側でこのセッションに紐づく状態を管理するために用いられる。 | OGZq4rpnijlc7lfr7nf1ZxPRT7_cE3mpugCt3sM4zYc |
| execution | 現在の認証フロー内で実行中のexecutionのID。executionとは、Keycloakにおける認証処理の実行単位のことです。 |
a417350-5baf-435c-bd0b-8b0350ce124b |
| tab_id | ブラウザのタブを識別するための一意のID。 | mqOdWrxsn5Q |
| client_data |
tab_idやclient_idなどの認証リクエスト送信時の情報をBase64エンコードした文字列。 |
eyJydSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODEMC9sb2dpbi9vYXV0aDIvY29kZS9rZXljbG9haylsInJ0IjoiY29kZSIsInN0ljoibW5fTHprRUFJeG1uRkptX0dvN3pxemZiMmg4elpaWU9IQ2N2MEJIVXNONEOifQ |
5.認証レスポンス
「4.ログイン操作」の手順で発生したhttp://localhost:8080/realms/demo/login-actions/authenticateリクエストのレスポンスが、「5.認証レスポンス」に該当します。

その後、「5.認証レスポンス」は「2.認証リクエストを送信」で設定したredirect_uri(http://localhost:8180/login/oauth2/code/keycloak)にリダイレクトされています。

このリダイレクトのクエリパラメータについて確認してみましょう。
http://localhost:8180/login/oauth2/code/keycloak?
state=mn_LzkEAIxmnFJm_Go7zqzfb2h8zZZYOHCcv0BbUst4%3D&
session_state=668b4767-5dbf-490f-9d96-fd91002aa9e1&
iss=http%3A%2F%2Flocalhost%3A8080%2Frealms%2Fdemo&
code=df519269-d169-4180-a3b6-571e431f60b0.668b4767-5dbf-490f-9d96-fd91002aa9e1.01f0dc5b-8345-4f66-9e9f-b13b9ae3862c
| パラメータ名 | 概要 | 値 |
|---|---|---|
| state | クライアントが生成した一意の文字列。 セッションと関連付けて保持することでCSRF対策などに利用される値。 「2.認証リクエストを送信」の stateパラメータと同一である必要がある。 |
fo4TJAkoOR4WJxIaC2ct5PtDA9BhB4RU3zhP2XR5KrE%3D |
| session_state | OP(Keycloak)がセッション管理のために用いるパラメータ。 | 668b4767-5dbf-490f-9d96-fd91002aa9e1 |
| iss | 認証レスポンスを発行したOP(Keycloak)の識別子を表すパラメータ。 | http%3A%2F%2Flocalhost%3A8080%2Frealms%2Fdemo |
| code | OP(Keycloak)の発行した認可コード。 | df519269-d169-4180-a3b6-571e431f60b0.668b4767-5dbf-490f-9d96-fd91002aa9e1.01f0dc5b-8345-4f66-9e9f-b13b9ae3862c |
次の2ステップはRP(クライアントアプリ)とOP(Keycloak)間での通信になります。
トークンの中身はRPの外に出してはいけないため、RP・OP間のみのやり取りとなっており、ブラウザからは詳細を閲覧することができません。
今回はRPのログから以下のステップに該当するリクエスト・レスポンスを確認します。
6.トークンリクエスト
RPのログから抜粋した、OPへのトークンリクエストです。
OpenID Endpoint Configurationにも載っているトークンエンドポイントにPOSTリクエストをおくっていることが確認できました。
2025-11-18T19:35:14.467+09:00 DEBUG 3493 --- [springboot-oidc] [http-nio-8180-exec-3] o.s.web.client.RestTemplate : HTTP POST http://localhost:8080/realms/demo/protocol/openid-connect/token
7.トークンレスポンス
上記の「6.トークンリクエスト」のログで確認されたスレッド名である [http-nio-8180-exec-3]に着目し、ログを確認すると、
ログメッセージ Response 200 OKが出力されており、リクエストが成功していることが確認できました。
2025-11-18T19:35:14.579+09:00 DEBUG 3493 --- [springboot-oidc] [http-nio-8180-exec-3] o.s.web.client.RestTemplate : Response 200 OK
8.コンテンツ返却
http://localhost:8180/user-areaへリダイレクト後、Status Codeから正常にコンテンツが返却されていることがわかります。
終わりに
実際に詳細を見ての感想
今回は認可コードフローをリクエスト単位で見ることで、OIDCの仕様で定められたやり取りと、OIDCの仕様範囲外でのやり取り(Keycloak・クライアントアプリそれぞれの仕様)の両方が混在していることがわかりました。
そこに気付くまで認証リクエストとアプリの仕様によるリクエストを混同してしまっていました。
今後、より複雑な構成のシステムに携わることもあるかと思うので、より正確で深い理解ができるよう勉強していきたいと思います。
今後に向けてのコメント
本記事では1つのRP(クライアントアプリ)が存在する構成でしたが、今後は複数RP(クライアントアプリ)の存在する構成でのSSOの実現や多要素認証などにも挑戦してみたいです。
参考














