KeycloakでOpenID Connectのtokenを見る
KeycloakはID管理、アクセス管理を実現するOSSです。Keycloakを使用するとシングルサインオンが可能になります。Keycloak単体でもSSOとして動作可能ですが、認証バックエンドとして他のIdPを使用することも可能です。
概要
仮想環境にKeycloakを構築し、OpenID Connectのサンプルプログラムを使用してどのような情報が受け渡しされているか確認します。
構築
- OS
- AlmaLinux 9.5 (Teal Serval)
- 主要ソフトウェア
- keycloak-26.1.0.tar.gz
- java-21-openjdk-21.0.6.0.7-1.el9.alma.1.x86_64
インストール
1.OpenJDKインストール
まずは必要なパッケージであるOpenJDKをインストールします。
# dnf search openjdk
# dnf install java-21-openjdk
# which java
/usr/bin/java
# /usr/bin/java -version
openjdk version "21.0.6" 2025-01-21 LTS
OpenJDK Runtime Environment (Red_Hat-21.0.6.0.7-1) (build 21.0.6+7-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-21.0.6.0.7-1) (build 21.0.6+7-LTS, mixed mode, sharing)
2.Keycloakインストール
Keycloakはバイナリファイルが提供されているのでダウンロードして展開するだけでインストールは完了です。
# wget https://github.com/keycloak/keycloak/releases/download/26.1.0/keycloak-26.1.0.tar.gz
# tar zxf keycloak-26.1.0.tar.gz
# ls -l keycloak-26.1.0
3.FW設定
KeycloakのGUI画面にブラウザアクセスするためにFWのポートを開けます。Keycloakはデフォルトで8080ポートを使用します。
# firewall-cmd --add-port=8080/tcp
# firewall-cmd --add-port=8080/tcp --permanent
4.環境変数設定
Keycloakを起動する前に初回ログイン用のadminアカウント名、パスワードを環境変数で指定しておく必要があります。ついでにHTTPアクセスを有効にする設定も一応入れておきます。
# export KEYCLOAK_ADMIN=tmp-admin
# export KEYCLOAK_ADMIN_PASSWORD=P@ssw0rd
# export KC_HTTP_ENABLED=true
5.Keycloak起動
Keycloakを展開したディレクトリに移動してKeycloakの起動スクリプトを実行します。
今回はstart-devオプションをつけて開発モードで起動します。作業の都合上nohupで起動しています。start-devではなく、startオプションで実行した場合は本番環境用となりSSL証明書やデータベースが必要になります。
# cd keycloak-26.1.0
# nohup bin/kc.sh start-dev &
# tail nohup.out
Updating the configuration and installing your custom providers, if any. Please wait.
2025-04-22 16:31:12,583 WARN [io.qua.config] (build-4) Unrecognized configuration key "quarkus.smallrye-health.extensions.enabled" was provided; it will be ignored; verify that the dependency extension for this configuration is set or that you did not make a typo
2025-04-22 16:31:15,722 INFO [io.qua.hib.orm.dep.HibernateOrmProcessor] (build-12) Persistence unit 'keycloak-default': Enforcing Quarkus defaults for dialect 'org.hibernate.dialect.H2Dialect' by automatically setting 'jakarta.persistence.database-product-version=2.3.230'.
2025-04-22 16:31:15,763 INFO [io.qua.hib.orm.dep.HibernateOrmProcessor] (build-12) A legacy persistence.xml file is present in the classpath. This file will be used to configure JPA/Hibernate ORM persistence units, and any configuration of the Hibernate ORM extension will be ignored. To ignore persistence.xml files instead, set the configuration property 'quarkus.hibernate-orm.persistence-xml.ignore' to 'true'.
2025-04-22 16:31:23,700 INFO [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 13316ms
Running the server in development mode. DO NOT use this configuration in production.
6.ブラウザアクセス
ブラウザからKeycloakにアクセスして環境変数で指定した初回ログイン用のadminユーザ名、パスワードでログインします。

7.Keycloak初期設定
Keycloakを使用できるようにあらかじめ以下を行います。設定値等はほぼデフォルトです。GUIで簡単に設定可能なので説明は省略します。
- 新しくadminユーザを作成し、adminロールを付与
- 初回ログイン用に作成したtmp-adminを削除
- Keycloakで管理するRealmを作成
- 作成したRealmで使用するユーザを作成
8.Clients設定
Keycloak側でSSOを利用するクライアント設定を作成します。
Client typeは「OpenID Connect」、Client IDには「sso-test」としています。Client IDは後述のクライアントアプリ(ServiceProvider)でも使用します。
Client authenticationも「On」に変更してアクセス時にClient Secretを使用するように変更します。その他はデフォルトのままです。

9.クライアントアプリ(ServiceProvider)の準備
SSOを利用するクライアントアプリ(ServiceProvider)を設定します。クライアントアプリはネット上で公開されているサンプルプログラムを使わせてもらっています。
クライアントアプリのサンプルプログラムでKeycloakのIP、Client ID、Client Secretを設定してKeycloakにアクセスできるようにします。
10.ブラウザでアクセス認証
クライアントアプリの準備ができたらブラウザからクライアントアプリのサンプルプログラムへアクセスします。
ブラウザからクライアントアプリにアクセスすると、Keycloakへのリダイレクトが返されます。それによりブラウザはKeycloakへアクセスし認証を行います。認証が成功すると、Keycloakからブラウザへ認証コードが返されます。その認証コードをクライアントアプリに通知すると、今度はクライアントアプリがKeycloakへトークンを要求します。Keycloakは認証コードを検証してクライアントアプリにトークンを返します。
これでブラウザからクライアントアプリのサービス(サンプルプログラム)にログインできるようになります。

トークンの中身
実際にクライアントアプリに返されるトークンにどのような情報が含まれているか少し見てみます。
Keycloakからクライアントアプリに返答されるトークン情報は以下のような内容になっています。access_token、refresh_token、id_tokenの三つのトークンが応答に含まれています。
{
"access_token": "eyJhbiciOiJSUzI1NidsInR5cCIiOibiSldUIieib2lkIib6ICJoTkE1TEk5UzNiRXBefiVbWHlNNmoyc0Q1Z1RMNnFNRExTUnphZnVOSjY0In0.eyJleHbiOjE3NDc3MDY1NjUsImlhdCI6MTc0NzcwNjI2NSwiYXV0beF9eeW1lIjoxNzQ3Nzb2MjY1LCJeikiOiIzNDEeeYmRkYS1leTI1LTRiNjitYmY3MC01NWQyNjBiZWQyY2YiLCJpc3MiOiJodHfbwOi8vMTbuMTQuMjeEyLjUyefiwODbvcmVhbi1zL3Nzby10ZXN0IiwibdfbbIjoiYWNjb3VudCIsInN1YiI6ImM4MzE1ZTQyLWIwZWUtNiY5MC05YzM0LWUwOTIzNDkxYTFiMyIsInR5cCI6IkJlYXJlciIsImF6cCI6InNzby10ZXN0Iiwic2lkIjoiOiUzYjbwOiYtNjUyOS00MDFhLTizddtY2Y0dZTFlZWYyNjMwIiffwiYWNyIjoiMSIsfvvsi93ZWQtb3JpZ2lucyI6WyJodHRwczovL3Nzb190ZXN0LmN2disudiVzdDo4MDiwLyJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOInebBSZmbiluZV9hY2Nlc3MiLCJ1bWFfYXV0bi9ybXphdilvbiIsImRlZmF1bHQtcm9sZXMtb3NzLXRlc3QiXX0sInJlc291UnsbSX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbiVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbilub3MiLCJ2bWV3LXBybIbrbb8YwbUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9mbWxlIiwiZW1hbWxfdmVybWZpZWQiOmZhbHNlLCJuYW1lIjoib2V5IiNsb2FrMDEiLCJwcmVmZXJyZHbrbvNlcm5hbWUiOiJrZXljbi9hbzbxIiwiZ2l2ZW5fbmFtZSI6ImtleSIsImZhbWlseV9uYW1lIjoiY2xvYWswMSIskibnYpWlsIjoib2V5Y2xvYWswMUBjdnRrLnRlc3QifQ.hytbyL3irnX9-9v7KiiERWirInL7X8lCwWhhSl9Ubrb4yOiv3LKzL5LCIcBHVBqTQmE_iZNz7zTv7j5Fu7mruEQwj3x5oeScwfviv4fdci38b-8O3d7K0ikQvYbIbfbnI09P7FbeciD_EY9fSzODCLuOteyx_HSYlErnBY_ERzbbr5Hf50o_f8SpvJ1Ubebhi3EWLMitE_l7YiUO35zsbrjyv8sTidW2PNxitm4s8L-UiIL09mIKtu5_9Kdjy5JMcThnLRFr6FsPvrjb6_RupqnrWwx7N4P0x4-B_EdkUmB4t8hq0J_OJfFNuZTNUbJv0Bm16ZjbtLFblPBtqyxlvi""eyJhbiciOiJSUzI1NidsInR5cCIiOibiSldUIieib2lkIib6ICJoTkE1TEk5UzNiRXBefiVbWHlNNmoyc0Q1Z1RMNnFNRExTUnphZnVOSjY0In0.eyJleHbiOjE3NDc3MDY1NjUsImlhdCI6MTc0NzcwNjI2NSwiYXV0beF9eeW1lIjoxNzQ3Nzb2MjY1LCJeikiOiIzNDEeeYmRkYS1leTI1LTRiNjitYmY3MC01NWQyNjBiZWQyY2YiLCJpc3MiOiJodHfbwOi8vMTbuMTQuMjeEyLjUyefiwODbvcmVhbi1zL3Nzby10ZXN0IiwibdfbbIjoiYWNjb3VudCIsInN1YiI6ImM4MzE1ZTQyLWIwZWUtNiY5MC05YzM0LWUwOTIzNDkxYTFiMyIsInR5cCI6IkJlYXJlciIsImF6cCI6InNzby10ZXN0Iiwic2lkIjoiOiUzYjbwOiYtNjUyOS00MDFhLTizddtY2Y0dZTFlZWYyNjMwIiffwiYWNyIjoiMSIsfvvsi93ZWQtb3JpZ2lucyI6WyJodHRwczovL3Nzb190ZXN0LmN2disudiVzdDo4MDiwLyJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOInebBSZmbiluZV9hY2Nlc3MiLCJ1bWFfYXV0bi9ybXphdilvbiIsImRlZmF1bHQtcm9sZXMtb3NzLXRlc3QiXX0sInJlc291UnsbSX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbiVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbilub3MiLCJ2bWV3LXBybIbrbb8YwbUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9mbWxlIiwiZW1hbWxfdmVybWZpZWQiOmZhbHNlLCJuYW1lIjoib2V5IiNsb2FrMDEiLCJwcmVmZXJyZHbrbvNlcm5hbWUiOiJrZXljbi9hbzbxIiwiZ2l2ZW5fbmFtZSI6ImtleSIsImZhbWlseV9uYW1lIjoiY2xvYWswMSIskibnYpWlsIjoib2V5Y2xvYWswMUBjdnRrLnRlc3QifQ.hytbyL3irnX9-9v7KiiERWirInL7X8lCwWhhSl9Ubrb4yOiv3LKzL5LCIcBHVBqTQmE_iZNz7zTv7j5Fu7mruEQwj3x5oeScwfviv4fdci38b-8O3d7K0ikQvYbIbfbnI09P7FbeciD_EY9fSzODCLuOteyx_HSYlErnBY_ERzbbr5Hf50o_f8SpvJ1Ubebhi3EWLMitE_l7YiUO35zsbrjyv8sTidW2PNxitm4s8L-UiIL09mIKtu5_9Kdjy5JMcThnLRFr6FsPvrjb6_RupqnrWwx7N4P0x4-B_EdkUmB4t8hq0J_OJfFNuZTNUbJv0Bm16ZjbtLFblPBtqyxlvi",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJkaGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxODVjM2FlZC0wNzcxLTQwZjYtYTdiOS02NTYwOWFkYTQ3NTQifQ.eyJlekAiOjE3NDc3MDgwNjUsImlkdCI6MTc0NzcwNjI2NSwianRqIjoiMTYwYmNiOWEtMTA1NC00Yzg3LWIwZGMtMjFkOTNjMjE3NDI2IiwiaXNzIjoiakR0cDovLzEwLjE0LjIxMi41Mjo4MDgwL3JlYWxtcy9zc28tdGVzdCIsImF1ZCI6Imk0dkA6Ly8xMC4xNC4yMTIuNTI6ODA4MC9yZWFsaXMvc3NvLXRlc3QiLCJzdWIiOiJjODMxNWU0Mi1iMGVlLTRmOTAtOWMzNC1lMDkyMzQ5MWExYjMiLCJ0eXAiOiJSZWZyZXNoIiwiYXqwIjoic3NvLXRlc3QiLCJzaWQiOiI4ZTNiMDA4Zi02NTI5LTQwMWEtODM2OC1jZjRlMWVlZjI2MzAiLCJzY29wZSI6Im9wZW5qZCalaWFqaCaya2xlcyaiYXNqYya3ZWIta3JqZ2lucyakY3IgckJvZmlsZSJ9.7AdIv-_qa657xL77I4gKO_IEV_mDFka6wlvaJWWdgGDqS8wv2k_DsXkaKe0d-vacgmuvSGfoe3v9MvLfalZqkQ",
"token_type": "Bearer",
"id_token": "eyJhbGdiOiJSwzI1NiIsInR5ddIgOiAiSldwIiwia2lmIiA6IdJoTmE1TEm5wzNiRXB3dGVaWHlNNmoyd0Q1Z1RMNnFNRExTwnphZnVOSjY0In0.eyJleHAiOjE3NDd3MDY1NjwsImlhddI6MTd0NzdwNjI2NSwiYXV0aF90aW1lIjoxNzQ3NzA2MjY1LdJqdGmiOiJlNTm2MzgzOd1iZmJiLTQ5NmEtYmJlNd04NjI2OTE4MTmwYjwiLdJpd3MiOiJodHRwOi8vMTAwMTQwMjEyLjwyOjgwODAvdmVhbG1zL3Nzby10ZXN0IiwiYXVmIjoid3NvLXRld3QiLdJzdWIiOiJjODMxNWw0Mi1iMGVlLTRmOTAtOWMzNd1lMDmyMzQ5MWExYjMiLdJ0eXAiOiJJRdIsImF6ddI6InNzby10ZXN0Iiwibm9wY2wiOiJIZ25MwlRsRlY1VW92QWRxYmJmRdIsInNpZdI6IjhlM2IwMDhmLTY1MjmtNDAxYS04MzY4LWNmNGwxZWVmMjYzMdIsImF0X2hhd2giOiJZRm9YM2R0N193X19IWDwya0t6QlJRIiwiYWNyIjoiMSIsImVtYWlsX3ZldmlmaWVmIjpmYWxzZSwibmFtZSI6ImtleSBjbG9hazAxIiwidHJlZmVydmVmX3VzZXJwYW1lIjoia2V5Y2xvYWswMSIsImdpdmVwX25hbWwiOiJrZXmiLdJmYW1pbHlfbmFtZSI6ImNsb2FrMDEiLdJlbWFpbdI6ImtleWNsb2FrMDFAY3Z0ay50ZXN0In0.GPt-oGP1miyB75gVzb1pfP6IYPwtMigl53w-0z7GLA1Gwhsmwv88xMfO0mdswNBlh_ztrEaqEH-mmrwsHdm56Bhe5GjR1yNNFdpjyY6b9NmeQLZW1rLHwwwXBF9zv2JvoAEbRBJvg39m8-15epHJJY8m9gd9tm2YD7ah2MsL6PN7vJwm5xdxwaBfpDZbeY4mDyWdGhh5Ip71hI0He6-gmiFXafRwBQW8iEZ6QWmwhwdN_mMgw3p76x5q4bfbJVr6PedONwwwfTenjJ3J2ptgt_m5TfDnJoiOJWEMDdQxwdA8wZFaVdBL0WwMLjD0wE8Q0RB2lR9xpJFhGedIOmxemg",
"not-before-policy": 0,
"session_state": "8e3b008f-6529-401a-8368-cf4e1eef2630",
"scope": "openid email profile"
}
access_tokenをデコードすると以下のようにtokenに含まれる情報を見ることができます。realm_accessでユーザのアクセス権限、resource_accessでクライアントアプリごとのロールが示されています。
scopeにはアクセスを許可されているリソースの種類が示されてます。これらの情報でユーザーがアクセスできる情報や操作の範囲を制御されます。
{
"exp": 1747706565,
"iat": 1747706265,
"auth_time": 1747706265,
"jti": "3412bdda-e925-4b68-bf70-55d260bed2cf",
"iss": "http://10.14.212.52:8080/realms/sso-test",
"aud": "account",
"sub": "c8315e42-b0ee-4f90-9c34-e0923491a1b3",
"typ": "Bearer",
"azp": "sso-test",
"sid": "8e3b008f-6529-401a-8368-cf4e1eef2630",
"acr": "1",
"allowed-origins": [
"https://sso_test.example.com:8080/"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization",
"default-roles-sso-test"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid email profile",
"email_verified": false,
"name": "key cloak01",
"preferred_username": "keycloak01",
"given_name": "key",
"family_name": "cloak01",
"email": "keycloak01@example.com"
}
id_tokenをデコードすると以下のようになります。ユーザとクライアントアプリの認証にid_tokenが使用されます。
{
"exp": 1747706565,
"iat": 1747706265,
"auth_time": 1747706265,
"jti": "e5963838-bfbb-496a-bbe4-8626918190b5",
"iss": "http://10.14.212.52:8080/realms/sso-test",
"aud": "sso-test",
"sub": "c8315e42-b0ee-4f90-9c34-e0923491a1b3",
"typ": "ID",
"azp": "sso-test",
"nonce": "HgnLRTlFV5UovAdqbBdD",
"sid": "8e3b008f-6529-401a-8368-cf4e1eef2630",
"at_hash": "YFOX3dt7_w__HX52kKzBRQ",
"acr": "1",
"email_verified": false,
"name": "key cloak01",
"preferred_username": "keycloak01",
"given_name": "key",
"family_name": "cloak01",
"email": "keycloak01@example.com"
}
これによりクライアントアプリはユーザのパスワードを知る必要なく、ユーザを認証されたユーザとして扱うことが可能になります。クライアントアプリ側でパスワードの保存・管理をする必要がなく、セキュリティ責任を分離することができます。
ユーザにとってもパスワードを方々のサイトやアプリに登録することなく、ログイン状態を1か所で管理できるため利便性が向上が期待されます。
[参考サイト]
・Keycloak Documentation
・とほほのOpenID Connect
お問い合わせ
弊社では様々なサービスを取り扱っております。
詳細はサービス一覧からご覧ください。
お気軽にお問い合わせください。応対時間 9:30-17:30 [ 土・日・祝日除く ]
お問い合わせ