はじめに
「うちのサービスに Google ログインを付けてください」という要求と「顧客企業の Azure AD で SSO してください」という要求は、まったく別の仕事に見えますが、Keycloak ではどちらも **Identity Brokering** という 1 つのメカニズムで解決されます。Keycloak がアプリケーションに対しては IdP の役割を果たしつつ、同時に外部 IdP に対してはクライアント(SP/RP)となって認証を仲介する構造です。
2026 年の認証環境は、この機能の価値をさらに高めています。passkey がデフォルトになりつつある流れの中でも、B2B SaaS の標準要件は依然として「顧客企業の IdP 連携」であり、[Keycloak 26](https://www.keycloak.org/docs/latest/release_notes/index.html) 系は Organizations 機能と Identity Brokering の改善を重ね、このシナリオをファーストクラスで扱っています。特に 26.x で preview として登場した **Identity Brokering API v2** は、長らくカスタム SPI で回避してきたブローカー拡張ポイントを標準化する変化です。
本記事では、brokering アーキテクチャと first login flow の動作原理、ソーシャル 3 社(Google/GitHub/Apple)の設定、外部 SAML/OIDC IdP 連携、account linking 戦略、トークン保存、B2B シナリオ、トラブルシューティングを順に扱います。
Identity Brokering アーキテクチャ
まず全体の流れを図で見てみましょう。
+-----------+ +---------------------------+ +-------------+
| Browser | | Keycloak (Broker) | | External IdP|
| | | realm: myrealm | | Google/SAML |
+-----+-----+ +------------+--------------+ +------+------+
| 1. アプリへアクセス、要ログイン | |
|--------------------------->| |
| 2. ログインページ | |
| (IdP ボタン一覧を表示) | |
|<---------------------------| |
| 3. "Sign in with Google" | |
|--------------------------->| |
| 4. AuthN request でリダイレクト (OIDC/SAML) |
|------------------------------------------------------------>
| 5. 外部 IdP で認証完了 |
<------------------------------------------------------------|
| 6. callback (code/assertion) を送付 |
|--------------------------->| |
| | 7. トークン交換、外部 identity|
| | の検証とユーザーマッピング |
| | 8. First Login Flow を実行 |
| 9. myrealm のトークン発行 | (新規/既存ユーザー処理) |
|<---------------------------| |
中核となる概念を整理します。
- 外部 IdP で認証された身元は、Keycloak 内部では **federated identity** として表現され、realm のローカルユーザーと連結(link)されます。
- 初めて見る federated identity が入ってくると **First Broker Login Flow** が実行され、ローカルユーザーの新規作成または既存アカウントとの連結を決定します。
- アプリケーションは外部 IdP の存在をまったく知りません。常に Keycloak が発行したトークンだけを受け取ります。**IdP を増やしても替えてもアプリのコードは無変更**というのが brokering の最大の利点です。
ソーシャルログイン設定 — Google、GitHub、Apple
3 つのプロバイダーはいずれも管理コンソールの Identity Providers メニューから追加しますが、コードによる管理のために kcadm ベースで整理します。共通の準備物は、各開発者コンソールで発行する client id と secret、そして Keycloak の redirect URI です。redirect URI は常に次の形式です。
https://kc.example.com/realms/myrealm/broker/IDP-ALIAS/endpoint
[Google Cloud Console](https://console.cloud.google.com/apis/credentials) で OAuth client を作成し、上記の redirect URI を登録してから作成します。
kcadm.sh create identity-provider/instances -r myrealm \
-s alias=google \
-s providerId=google \
-s enabled=true \
-s 'config.clientId=GOOGLE_CLIENT_ID' \
-s 'config.clientSecret=GOOGLE_CLIENT_SECRET' \
-s 'config.defaultScope=openid profile email' \
-s 'config.hostedDomain=example.com'
`hostedDomain` は Google Workspace の組織ドメインでログイン可能なアカウントを制限するオプションです。社内サービスなら必ず設定すべきです。ただしこの値はクライアント側のヒントでもあるため、Keycloak が ID token の hd クレームを検証するよう Validate hosted domain まで有効にするのが安全です。
GitHub
GitHub は OIDC ではなく純粋な OAuth2 プロバイダーのため ID token がなく、Keycloak が user API を呼び出してプロフィールを取得します。
kcadm.sh create identity-provider/instances -r myrealm \
-s alias=github \
-s providerId=github \
-s enabled=true \
-s 'config.clientId=GITHUB_CLIENT_ID' \
-s 'config.clientSecret=GITHUB_CLIENT_SECRET' \
-s 'config.defaultScope=read:user user:email'
注意すべきは**メール非公開設定のユーザー**です。scope に user:email がないとメールが null で入ってきて、first login flow がメール入力画面で止まります。また GitHub のメールには検証済みかどうかの情報が付随するため、未検証メールでの account linking を許可するとアカウント乗っ取りのベクターになります。後述の linking の節で詳しく扱います。
Apple
Sign in with Apple は 3 つの中で最も厄介です。固定の client secret の代わりに **p8 秘密鍵で署名した JWT を client secret として使用**し、有効期間が最長 6 か月のため定期的な更新が必要です。
kcadm.sh create identity-provider/instances -r myrealm \
-s alias=apple \
-s providerId=apple \
-s enabled=true \
-s 'config.clientId=com.example.service' \
-s 'config.teamId=APPLE_TEAM_ID' \
-s 'config.keyId=APPLE_KEY_ID' \
-s 'config.p8Content=P8_PRIVATE_KEY_CONTENT'
Apple 特有の罠が 2 つあります。第一に、ユーザーの氏名とメールは**最初の認可時に一度だけ**渡されます。first login flow が失敗して再試行すると氏名が永遠に空のままになるため、Apple 開発者コンソールでアプリの Sign in with Apple 利用権限をリセットして再テストする必要があります。第二に、ユーザーがメールを隠す(Hide My Email)を選択すると、privaterelay.appleid.com ドメインのリレーアドレスが入ってきます。メールベースの account linking が意味を失うケースなので、ポリシーとして考慮すべきです。
外部 SAML / OIDC IdP のブローカリング
企業顧客の IdP を連携するケースです。OIDC IdP は discovery URL さえあれば最も簡単です。
OIDC IdP(例: 顧客企業の Entra ID)
kcadm.sh create identity-provider/instances -r myrealm \
-s alias=customer-a-oidc \
-s providerId=oidc \
-s enabled=true \
-s 'config.useJwksUrl=true' \
-s 'config.issuer=https://login.microsoftonline.com/TENANT_ID/v2.0' \
-s 'config.authorizationUrl=https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/authorize' \
-s 'config.tokenUrl=https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token' \
-s 'config.clientId=ENTRA_APP_ID' \
-s 'config.clientSecret=ENTRA_SECRET' \
-s 'config.defaultScope=openid profile email' \
-s 'config.validateSignature=true'
SAML IdP はメタデータ XML をインポートするのが定石です。手動設定の場合の主要項目は次のとおりです。
kcadm.sh create identity-provider/instances -r myrealm \
-s alias=customer-b-saml \
-s providerId=saml \
-s enabled=true \
-s 'config.entityId=https://kc.example.com/realms/myrealm' \
-s 'config.singleSignOnServiceUrl=https://idp.customer-b.com/sso/saml' \
-s 'config.nameIDPolicyFormat=urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress' \
-s 'config.validateSignature=true' \
-s 'config.wantAssertionsSigned=true' \
-s 'config.signatureAlgorithm=RSA_SHA256' \
-s 'config.postBindingResponse=true'
SAML 連携でセキュリティ上妥協できない項目は **validateSignature と wantAssertionsSigned** です。署名検証のない SAML は assertion の偽造に対して無防備です。証明書の期限切れも定番の障害原因のため、IdP 証明書の有効期限を監視対象に入れるべきです。
Account Linking 戦略 — メール重複の処理
brokering の運用で最もポリシー決定が難しいポイントです。デフォルトの First Broker Login Flow は次の順序で動作します。
federated identity の初回流入
|
v
+-------------------------------+
| Review Profile (既定: 常に) | ユーザーがプロフィールを確認/修正
+-------------------------------+
|
v
+-------------------------------+
| Create User If Unique | メール/username の重複がなければ
+-------------------------------+ ローカルユーザーを新規作成
| (重複発見時)
v
+-------------------------------+
| Handle Existing Account |
| - Confirm link existing | 「既存アカウントと連結しますか?」
| - Verify via email | メール検証リンクを送付
| - または re-authenticate | 既存パスワードで再認証
+-------------------------------+
ポリシーの選択肢は大きく 3 つです。
| 戦略 | 動作 | 適するケース |
| --- | --- | --- |
| 自動連結 | メール一致なら無条件で link | 社内専用、すべての IdP が信頼可能 |
| 検証後に連結 | メール検証または再認証後に link | 一般的な B2C のデフォルト |
| 連結禁止 | 重複時はエラー、手動対応 | 規制業種、高セキュリティ |
ここで絶対に忘れてはいけないセキュリティ原則があります。**未検証のメールを根拠に自動 linking をしてはいけません。**攻撃者が被害者のメールアドレスで登録した外部 IdP アカウント(メール検証を強制しない IdP)を作ってログインすると、被害者の既存アカウントに連結され、アカウントを乗っ取れてしまいます。Trust Email オプションは、当該 IdP がメール検証を保証していると確信できる場合にのみ有効にすべきです。
既存ユーザーが設定画面から自分でソーシャルアカウントを連結するシナリオは、first login flow ではなく **Account Console の Linked Accounts** 機能、または AIA(Application Initiated Action)に類似した idp_link フローで処理します。アプリケーションから直接連結 URL を作る場合は、client-initiated account linking の仕様に従って nonce と hash を含む URL を構成します。
Attribute と Claim のマッピング
外部 IdP が送ってきたクレーム・attribute をローカルユーザーへ反映するのは **Identity Provider Mappers** の役割です。第 1 回で扱った Protocol Mapper が「出ていくトークン」を作るのに対し、IdP mapper は「入ってくる身元」を変換します。
OIDC IdP の department クレームをユーザー attribute へ
kcadm.sh create identity-provider/instances/customer-a-oidc/mappers -r myrealm \
-s name=dept-import \
-s identityProviderAlias=customer-a-oidc \
-s identityProviderMapper=oidc-user-attribute-idp-mapper \
-s 'config.claim=department' \
-s 'config."user.attribute"=department' \
-s 'config.syncMode=FORCE'
SAML attribute を realm role へ
kcadm.sh create identity-provider/instances/customer-b-saml/mappers -r myrealm \
-s name=admin-role-mapper \
-s identityProviderAlias=customer-b-saml \
-s identityProviderMapper=saml-role-idp-mapper \
-s 'config."attribute.name"=memberOf' \
-s 'config."attribute.value"=CN=ServiceAdmins' \
-s 'config.role=platform-admin' \
-s 'config.syncMode=FORCE'
最も重要な設定は **syncMode** です。
- IMPORT: 初回ログイン時に一度だけ反映。以降の IdP 側の変更は無視。
- FORCE: ログインのたびに IdP の値で上書き。
- LEGACY: 旧互換動作(使用非推奨)。
組織情報やロールのように IdP が真実の源であるデータは FORCE に、ユーザーが Keycloak 側で直接修正できるプロフィールは IMPORT にするのが一般的な分離基準です。FORCE マッピングでロールを付与する場合、**IdP 側で権限を剥奪されたユーザーのロールが次回ログイン時に一緒に剥奪されるか**を必ずテストすべきです。
ブローカートークンの保存と Stored Tokens API
IdP 設定の Store Tokens オプションを有効にすると、Keycloak が外部 IdP の access/refresh token を保存します。用途は明確です。**外部 IdP の API をユーザーの代わりに呼び出す**ケースです。たとえば GitHub ログインユーザーのリポジトリ一覧を読む機能なら、アプリケーションは broker token retrieval エンドポイントから GitHub の access token を取得します。
GET /realms/myrealm/broker/github/token HTTP/1.1
Host: kc.example.com
Authorization: Bearer KEYCLOAK_ACCESS_TOKEN
この呼び出しが成功するには 2 つの条件が必要です。
1. IdP 設定で Store Tokens および Stored Tokens Readable を有効化
2. 呼び出すユーザーに broker クライアントの **read-token** ロールを付与
kcadm.sh add-roles -r myrealm \
--uusername alice \
--cclientid broker \
--rolename read-token
運用観点での注意点は、保存された外部トークンの寿命です。Keycloak は外部 refresh token による自動更新を試みますが、外部 IdP がトークンを失効させると 401 がそのまま伝播します。アプリケーションは stored token の呼び出し失敗時に再認可へ誘導する(当該 IdP で再ログインさせる)経路を必ず実装しておくべきです。
Keycloak 26 の Identity Brokering API v2(Preview)
Keycloak 26.x では **Identity Brokering の内部 SPI を再設計した v2 API が preview として導入**されました。従来の brokering 拡張は AbstractIdentityProvider の継承と散在するコールバックの組み合わせで実装する必要があり、カスタム IdP(例: 国内の本人確認事業者、レガシーな社内認証ゲートウェイ)連携コードはバージョンアップのたびに壊れやすいものでした。v2 は、認証リクエストの生成、レスポンスの処理、identity の変換、linking の判断という拡張ポイントを、より明示的な契約に分離する方向です。preview 段階のためプロダクション適用は時期尚早ですが、カスタム brokering コードを持つチームなら、移行計画を今から検討する価値があります。詳細は[公式リリースノート](https://www.keycloak.org/docs/latest/release_notes/index.html)を参照してください。
企業シナリオ — 顧客企業 IdP 連携の B2B SSO
B2B SaaS で「顧客企業ごとに自社 IdP で SSO」という要求を brokering で解決する際の設計ポイントです。
+--------------------------------------+
| Keycloak realm: saas |
Customer A users --> | IdP: customer-a-oidc (Entra ID) |
Customer B users --> | IdP: customer-b-saml (Okta) |
Direct users --> | Local username/password + passkey |
| |
| Organizations 機能でドメインをマッピング |
| a-corp.com -> customer-a-oidc |
| b-inc.com -> customer-b-saml |
+------------------+-------------------+
|
v
SaaS Application (単一クライアント)
- **Home IdP Discovery**: ログイン画面に IdP ボタンを数十個並べるわけにはいかないため、メールドメインで IdP を自動ルーティングします。Keycloak の Organizations 機能がドメインと IdP のマッピングおよびメンバーシップ管理を提供するため、26.x 基準ではこの機能を最優先で検討すべきです。
- **kc_idp_hint**: 顧客企業専用の入口 URL からログイン画面をスキップして特定の IdP へ直接送るときに使います。
https://kc.example.com/realms/saas/protocol/openid-connect/auth
?client_id=saas-app
&response_type=code
&scope=openid
&redirect_uri=https://app.example.com/callback
&kc_idp_hint=customer-a-oidc
- **テナント分離 vs 単一 realm**: 顧客ごとに realm を分離すれば分離は完璧ですが、realm 数が増えるほど運用・メモリコストが増大します。単一 realm + 複数 IdP + Organizations の組み合わせが 2026 年時点の主流パターンであり、規制で分離が強制される顧客だけを別 realm に切り出すハイブリッドが現実的です。
- **オンボーディングの自動化**: 顧客企業 IdP の追加は反復作業のため、Admin REST API や Terraform でテンプレート化します。新規顧客のオンボーディングが「チケット処理」ではなく「セルフサービス設定」になるのが目標です。
カスタム First Broker Login Flow
デフォルトの flow を複製して要件に合わせて変形するのが定石です。よく使う変形を 3 つ紹介します。
1. **Review Profile を無効化**: IdP のデータが信頼できるなら、ユーザー確認画面を省略して摩擦を減らします。Review Profile の実行を OFF に変えるだけです。
2. **信頼できる IdP の自動連結**: 社内 IdP のようにメール検証が保証される場合、Handle Existing Account の下に Automatically Set Existing User 系の executor を配置し、確認手順なしで連結します。外部のソーシャル IdP には絶対に適用しません。
3. **追加情報の収集**: 利用規約への同意、部署選択といったステップを、カスタム Required Action またはカスタム authenticator として挿入します。
デフォルト flow を複製して IdP に指定
kcadm.sh create authentication/flows/first%20broker%20login/copy -r myrealm \
-s newName=corp-first-login
kcadm.sh update identity-provider/instances/customer-a-oidc -r myrealm \
-s 'config.firstBrokerLoginFlowAlias=corp-first-login'
flow の変更後は、必ずシークレットブラウザウィンドウで、新規ユーザー・既存ユーザー・メール重複の 3 ケースをすべて回帰テストすべきです。flow の設定ミスは全ユーザーのログイン不能に直結する領域です。
トラブルシューティング
現場でよく遭遇する brokering 障害を症状別に整理します。
| 症状 | 原因 | 解決 |
| --- | --- | --- |
| invalid_redirect_uri | 外部 IdP に broker endpoint が未登録 | redirect URI を IdP コンソールに正確に登録 |
| Page Expired | first login flow 中の戻る/再試行 | flow に再進入、Apple は権限リセット後に再試行 |
| メールなしでユーザー作成が停止 | GitHub の非公開メール、scope 欠落 | user:email scope を追加 |
| ログインループ | broker と IdP のセッション/プロンプト設定の衝突 | prompt パラメータ、IdP セッションポリシーを確認 |
| SAML Invalid signature | IdP 証明書の交換、メタデータ不一致 | メタデータ再インポート、証明書期限の監視 |
| 同じ人物のアカウントが 2 つ | linking ポリシー不在で新規作成された | 重複アカウントを統合後、linking flow を整備 |
| ログアウトしても IdP セッションが残る | 外部 IdP へ logout が伝播しない | IdP 設定の backchannel/front-channel logout 対応を確認 |
デバッグツールは 2 つが中核です。第一に、管理コンソールの **Events**(Login Events で IDENTITY_PROVIDER_LOGIN、FIRST_BROKER_LOGIN などのイベントタイプをフィルタリング)。第二に、サーバーログレベルの調整です。
kc.sh start --log-level=INFO,org.keycloak.broker:DEBUG,org.keycloak.saml:DEBUG
SAML の問題は、ブラウザ拡張(SAML-tracer)で assertion の原文をキャプチャし、NameID 形式と attribute 名を直接確認するのが最速です。
運用ベストプラクティス
brokering の構成は、作ることよりも維持することの方が難しいものです。運用フェーズで押さえるべき項目を整理します。
資格情報と証明書のライフサイクル管理
外部 IdP とやり取りする秘密値にはすべて有効期限があります。期限切れの際にどんな症状が出るかまで併せて覚えておくと、障害対応が速くなります。
| 項目 | 一般的な寿命 | 期限切れ時の症状 |
| --- | --- | --- |
| Apple client secret(署名 JWT) | 最長 6 か月 | invalid_client エラー |
| ソーシャル IdP の client secret | プロバイダーのポリシー次第 | unauthorized_client エラー |
| SAML IdP の署名証明書 | 1〜3 年 | Invalid signature エラー |
| 外部 OIDC IdP の JWKS 鍵 | 随時ローテーション | 一時的なトークン検証失敗 |
Apple secret のように更新が予測可能な項目は、CI スケジュールで自動化するのが安全です。
毎月 1 回 CI で実行: p8 鍵から新しい client secret(JWT)を生成して反映
NEW_SECRET=$(python3 generate_apple_secret.py \
--team APPLE_TEAM_ID --key-id APPLE_KEY_ID \
--key-file AuthKey.p8 --client-id com.example.service)
kcadm.sh update identity-provider/instances/apple -r myrealm \
-s "config.clientSecret=$NEW_SECRET"
イベントを SIEM へ送る
brokering 関連のイベントはセキュリティ監視の一次シグナルです。イベント保存を有効にし、IDENTITY_PROVIDER_LOGIN や FEDERATED_IDENTITY_LINK といったタイプを収集対象に含めます。
kcadm.sh update events/config -r myrealm \
-s eventsEnabled=true \
-s eventsExpiration=2592000 \
-s 'enabledEventTypes=["LOGIN","LOGIN_ERROR","IDENTITY_PROVIDER_LOGIN","IDENTITY_PROVIDER_FIRST_LOGIN","IDENTITY_PROVIDER_LINK_ACCOUNT","FEDERATED_IDENTITY_LINK","REMOVE_FEDERATED_IDENTITY"]'
特に **FEDERATED_IDENTITY_LINK イベントの急増**は、linking ポリシーの隙を突く攻撃の試みである可能性があるため、アラートルールを設定しておくことをおすすめします。カスタム event listener SPI で Kafka や syslog へ直接流す構成も一般的です。
定期点検チェックリスト
- 四半期ごとに未使用の IdP(直近のログインイベントが 0 件)を無効化または削除します。
- IdP ごとのログイン成功率をダッシュボード化し、特定の顧客企業 IdP の品質低下を早期に検知します。
- first broker login flow の変更後は、新規/既存/メール重複の 3 ケースの E2E テストを再実行します。
- 顧客企業 IdP のメタデータ URL を定期的にポーリングし、証明書の交換を自動で取り込みます。
- realm export を定期バックアップし、IdP 設定の形状を保存します。
- Store Tokens を有効にした IdP は、保存トークンの有効性を定期的にサンプル検査し、失敗時に再認可フローが動作するか確認します。
- Keycloak のバージョンアップ前に、カスタム first broker login flow と brokering 関連 SPI の互換性をステージングで先に検証します。
おわりに
Identity Brokering は「ソーシャルログインを付ける」という小さな機能として始まりますが、最終的には B2B SSO とアカウントライフサイクルポリシー全体を支える基盤になります。要点をまとめます。
- アプリケーションは Keycloak だけを見て、IdP の追加・交換は broker 設定で吸収します。
- ソーシャル 3 社はそれぞれの罠(Google の hd 検証、GitHub のメール scope、Apple の 1 回限りのプロフィールとシークレット更新)を熟知すべきです。
- account linking はセキュリティ上の決定です。未検証メールに基づく自動連結はアカウント乗っ取りのベクターです。
- IdP mapper の syncMode はデータの所有権に応じて IMPORT / FORCE を使い分けます。
- B2B は単一 realm + Organizations + ドメインルーティングが基本パターンであり、カスタム brokering コードは API v2 への移行を準備します。
参考資料
- [Keycloak Server Administration Guide — Integrating Identity Providers](https://www.keycloak.org/docs/latest/server_admin/index.html#_identity_broker)
- [Keycloak Documentation](https://www.keycloak.org/documentation)
- [Keycloak Release Notes](https://www.keycloak.org/docs/latest/release_notes/index.html)
- [Keycloak 26.6.0 Released](https://www.keycloak.org/2026/04/keycloak-2660-released)
- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)
- [SAML 2.0 Core Specification](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf)
- [RFC 6749 — The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
- [RFC 9700 — Best Current Practice for OAuth 2.0 Security](https://datatracker.ietf.org/doc/html/rfc9700)
- [Sign in with Apple Documentation](https://developer.apple.com/documentation/signinwithapple)
- [GitHub OAuth Apps Documentation](https://docs.github.com/en/apps/oauth-apps)
- [Google Identity — OpenID Connect](https://developers.google.com/identity/openid-connect/openid-connect)
- [OAuth 2.1 draft](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/)
현재 단락 (1/240)
「うちのサービスに Google ログインを付けてください」という要求と「顧客企業の Azure AD で SSO してください」という要求は、まったく別の仕事に見えますが、Keycloak ではどち...