Contents
Keycloak 26.0(Red Hat ビルド)の新機能と OIDC 標準サポート
Keycloak 26.0 は OpenID Connect の標準フローをそのまま利用できるよう大幅に改善されています。PKCE がデフォルトで有効になるほか、RP‑initiated ログアウトやセッション同期エンドポイントが新たに追加され、Spring Security 6 とのシームレスな連携が可能です。本節では主な機能と導入メリットを概観します。
主な変更点の概要
- PKCE が自動的に有効化(設定不要でコードインジェクションリスク低減)
- RP‑initiated ログアウト API の提供により、シングルサインアウトが容易に実装可能
- セッション同期エンドポイント で外部アプリケーションと認証状態を共有できる
OpenID Connect と PKCE の統合的な解説
この章では OIDC の全体像と、PKCE がどのように認可コードフローを保護するかをまとめて説明します。重複して記載されていた箇所を一つに統合し、読者が一目で理解できる構成にしています。
OIDC の基本フローモデル(概要)
OpenID Connect は OAuth 2.0 の認可コードフローをベースに ID トークンを付加したプロトコルです。クライアントは authorization‑code を取得し、トークンエンドポイントでアクセストークンと ID トークンを交換します。
PKCE(Proof Key for Code Exchange)とは
PKCE は認可コードフローに対する追加の検証手段です。クライアントはランダムな code verifier を生成し、ハッシュ化した code challenge を認可リクエストに付与します。トークン交換時に同じ verifier を送信することで、認可コードが第三者に盗まれても不正利用できないようにします。
- 利点
- 公開クライアント(SPA やモバイル)でも安全に認証可能
- サーバーサイドでの client‑secret が不要になるケースが増える
Keycloak 26.0 では「Enable PKCE」オプションがデフォルトでオンになり、開発者は設定を意識せずにこの保護機構を利用できます。
Realm とクライアントの基本概念
Realm と Client の関係性を正しく把握することは、Keycloak を運用する上で最も重要です。本節ではそれぞれの役割と設定ポイントを簡潔に解説します。
Realm の概要(導入文)
Realm はユーザー・ロール・クライアントなどの認可情報を論理的に分離する単位です。開発環境と本番環境で別々の Realm を作成すれば、設定ミスやデータ漏洩リスクを低減できます。
- 主な要素
- ユーザー管理(登録・パスワードポリシー)
- ロール定義とロールマッピング
- クライアント(外部アプリケーション)の登録
Client の概要(導入文)
Client は OIDC における client‑id と client‑secret を持ち、認可サーバーとのやり取りを行うエンティティです。Spring Boot アプリではリダイレクト URI を /login/oauth2/code/* に合わせる必要があります。
- 必須項目
Client ID(例:spring-boot-app)Client Secret(confidential クライアントの場合必須)Valid Redirect URIs(例:http://localhost:8080/login/oauth2/code/keycloak)
Spring Boot 3.x と Spring Security 6 の基本構成
Spring Boot 3 系は Java 17+ を前提にモジュール化が進み、Spring Security 6 は OAuth2/OIDC クライアント機能をコアに据えています。本節ではプロジェクトの雛形作成から依存関係管理までを網羅的に解説します。
プロジェクト雛形の作り方(導入文)
Spring Initializr で必要なスターターを選択し、ビルドツールと Java バージョンを指定すれば、認証連携に必要な土台が自動生成されます。
|
1 2 3 4 5 6 |
plugins { id("org.springframework.boot") version "3.2.0" kotlin("jvm") version "1.9.0" } java.sourceCompatibility = JavaVersion.VERSION_17 |
依存関係とバージョン管理(導入文)
Spring Boot の BOM (spring-boot-dependencies) を dependencyManagement にインポートすれば、個別のバージョン指定は不要です。これにより Keycloak Adapter 等旧来の依存関係を排除し、標準 OAuth2 フローだけで完結できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> |
Keycloak 側の Realm/Client 作成と Spring 設定
Keycloak 管理コンソールで行う設定手順と、Spring アプリ側に必要な application.yml の記述例を具体的に示します。
Realm と Client の作成手順(導入文)
以下のステップに従えば、数分で OIDC 認証が利用できる環境が完成します。設定ミスを防ぐため、各項目は正確に入力してください。
- Realm 作成 →
Add realm→ 任意の名前(例:demo-realm)で保存 - Client 登録 →
Clients > Create - Client ID:
spring-boot-app - Client Protocol:
openid-connect - Access Type:
confidential(PKCE でも secret が必要) - Valid Redirect URIs:
http://localhost:8080/login/oauth2/code/keycloak - Credentials タブで自動生成された
client-secretをコピー
Spring 側設定例(導入文)
application.yml に OIDC クライアント情報を記述すれば、Spring Security が自動的に認可コードフローと PKCE を有効化します。環境変数でシークレットを管理すると、Docker/K8s との相性が良くなります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
spring: security: oauth2: client: registration: keycloak: client-id: spring-boot-app client-secret: ${KEYCLOAK_CLIENT_SECRET} authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" scope: openid, profile, email provider: keycloak: issuer-uri: https://keycloak.example.com/realms/demo-realm |
OIDC 認証フローとトークン検証の実装
Spring Security が提供する oauth2Login() によって、認可コードフロー+PKCE が自動的に有効化されます。本節ではフロー全体像とカスタム Claim マッピング方法を解説します。
認可コードフロー+PKCE の構成(導入文)
Spring Security は内部で code verifier を生成し、トークンエンドポイントに送信するため、開発者はコードレベルでの実装が不要です。
- Authorization Request:
/oauth2/authorization/keycloakへリダイレクト - Code Exchange: PKCE verifier と共に認可コードをトークンエンドポイントへ送信
|
1 2 3 4 5 6 7 8 9 |
@Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authz -> authz .requestMatchers("/", "/error").permitAll() .anyRequest().authenticated()) .oauth2Login(); // OIDC ログインを有効化 return http.build(); } |
アクセストークン・IDトークンの自動検証とカスタム Claim マッピング(導入文)
JwtDecoder が JWK エンドポイントから公開鍵を取得し、署名や exp、aud などを自動で検証します。追加クレームは OAuth2UserService を拡張して取得できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Bean OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() { OidcUserService delegate = new OidcUserService(); return request -> { OidcUser user = delegate.loadUser(request); Map<String, Object> claims = new HashMap<>(user.getClaims()); String department = (String) claims.get("department"); Set<GrantedAuthority> authorities = new HashSet<>(user.getAuthorities()); if ("admin".equals(department)) { authorities.add(new SimpleGrantedAuthority("ROLE_DEPT_ADMIN")); } return new DefaultOidcUser(authorities, user.getIdToken(), user.getUserInfo()); }; } |
ロール/権限マッピングと API 保護
Keycloak の Realm Role を Spring Security の GrantedAuthority に変換すれば、メソッドレベルの認可がシンプルに実装できます。
Role → GrantedAuthority の変換ロジック(導入文)
以下のコンバータを JwtAuthenticationConverter に登録するだけで、トークン内のロール情報が自動的に Spring の権限へマッピングされます。
|
1 2 3 4 5 6 7 8 9 10 11 |
@Component public class KeycloakRoleConverter implements Converter<Jwt, Collection<GrantedAuthority>> { @Override public Collection<GrantedAuthority> convert(Jwt jwt) { List<String> roles = jwt.getClaimAsStringList("realm_access.roles"); return roles.stream() .map(r -> new SimpleGrantedAuthority("ROLE_" + r.toUpperCase())) .collect(Collectors.toSet()); } } |
@PreAuthorize でエンドポイントを保護する例(導入文)
@PreAuthorize アノテーションにロール名を指定すれば、認可チェックが宣言的に行われます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@RestController @RequestMapping("/api") public class SampleController { @GetMapping("/admin") @PreAuthorize("hasAuthority('ROLE_ADMIN')") public String adminEndpoint() { return "管理者専用データ"; } @GetMapping("/user") @PreAuthorize("hasAnyAuthority('ROLE_USER','ROLE_ADMIN')") public String userEndpoint() { return "ユーザー向け情報"; } } |
デプロイ・運用、マイグレーション、トラブルシューティング
本番環境でのコンテナ化や Kubernetes 展開手順、旧 Spring Adapter からの移行ポイント、およびよくあるエラーと対処法をまとめます。
Docker / Kubernetes での連携デプロイ例(導入文)
公式 Keycloak イメージと Spring Boot アプリを docker‑compose または Helm chart で組み合わせるだけで、開発・本番環境が統一的に構築できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# docker-compose.yml version: "3.9" services: keycloak: image: quay.io/keycloak/keycloak:26.0.0 environment: - KEYCLOAK_ADMIN=admin - KEYCLOAK_ADMIN_PASSWORD=admin ports: - "8081:8080" command: start-dev --http-relative-path /auth app: build: . environment: - SPRING_PROFILES_ACTIVE=prod - KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET} ports: - "8080:8080" depends_on: - keycloak |
K8s 環境では codecentric/keycloakx Helm chart と Spring Boot の Deployment を組み合わせ、Ingress に OIDC のリダイレクト URI(例:/login/oauth2/code/keycloak)を設定します。
旧 Spring Adapter からのマイグレーション手順(導入文)
Red Hat が提供する移行ガイドに沿って、従来の keycloak-spring-boot-starter 系統を除去し、標準 OAuth2 クライアントへ置き換えます。
| 旧方式 | 新方式 | 主な変更点 |
|---|---|---|
keycloak-spring-boot-starter |
Spring Security OIDC クライアント | アダプタ削除 → 標準フロー使用 |
KeycloakSpringBootConfigResolver |
spring.security.oauth2.client.provider.keycloak.issuer-uri |
設定ファイルがシンプル化 |
KeycloakAuthenticationProvider |
JwtAuthenticationConverter |
トークン検証ロジックが自動化 |
典型的なエラーと対処法(導入文)
実装時に遭遇しやすい問題とその解決策を一覧で示します。設定ミスの早期発見に役立ちます。
- 401/403 エラー:
audクレームがclient-idと一致しているか確認。Keycloak の「Valid Redirect URIs」も正しいかチェック。 - CORS 問題:Spring Security で CORS 設定を有効化し、Keycloak 側でも同一オリジンポリシーを許可する。
- aud クレーム不一致:
application.ymlのissuer-uriが対象 Realm を正しく指しているか検証。
まとめ
- Keycloak 26.0 は PKCE と標準 OIDC ログアウト機能をデフォルトで提供し、Spring Security 6 と即時統合可能です。
- Spring Boot 3.x + Spring Security 6 の
oauth2Login()によって認可コードフローとトークン検証が自動化され、実装コストを大幅に削減できます。 - Realm/Client 設定 は管理コンソールでシンプルに完了し、
application.ymlへissuer-uriとクレデンシャルを書くだけで接続が確立します。 - ロールマッピング はカスタム
JwtAuthenticationConverter/KeycloakRoleConverterによって実装し、@PreAuthorizeでメソッド単位の保護が可能です。 - Docker/Kubernetes 環境 では公式イメージと Helm chart を活用し、シークレットは環境変数または K8s Secret で安全に管理します。
- 旧 Adapter からの移行 は Red Hat のマイグレーションガイドに従い、設定を標準 OAuth2 に置き換えるだけで完了します。
以上の手順とベストプラクティスに沿って構築すれば、最新の Keycloak と Spring Security を組み合わせた安全・拡張性の高い認証基盤が短時間で実現できます。