マイクロサービス間でユーザーの権限を安全に引き回すToken Exchange。KeycloakのRFC 8693実装を、標準V2とレガシーV1の違い、audienceの絞り込み、機能フラグの扱いまで現場目線で整理します。
マイクロサービス構成では、フロントに立つサービスが受け取ったユーザーのトークンを、そのまま奥のサービスに渡してよいのか、という問いに必ず突き当たります。素朴に転送すると、奥のサービスから見て「宛先(audience)が自分ではないトークン」を検証させることになり、audience検証を緩めざるを得なくなります。かといってサービスアカウントで叩けば「誰の依頼で動いているか」が失われます。この隙間を埋めるのが OAuth 2.0 Token Exchange(RFC 8693)であり、Keycloakはこれを正式機能として実装しています。本稿では標準実装(V2)を軸に、レガシー(V1)との差、audienceの扱い、機能フラグの流儀までを実務目線で整理します。バージョン依存の記述は新しめのKeycloak(Quarkus版・26系)を基準にしていますので、採用時は必ず公式ドキュメントで最新の挙動をご確認ください。
01Token Exchangeが解く課題
Token Exchangeは、あるトークンを別のトークンに「交換」する仕組みです。RFC 8693は、クライアントが手元のトークン(subject token)を認可サーバーに提示し、別の宛先・別のスコープに絞られた新しいトークンを受け取るフローを標準化しています。Keycloakにおける典型的な使いどころは、同一レルム内でサービスAが持つトークンを、サービスB向けのトークンへ交換する「内部→内部」の権限委譲です。
- audience(宛先)の付け替え:Aにしか向いていないトークンを、B向けの正しいaudienceを持つトークンに変換する。奥のサービスは自分宛のトークンだけを検証すればよくなります。
- 権限の絞り込み(downscoping):交換のたびにスコープやaudienceを狭められるため、奥へ行くほど権限が縮小する、最小権限に沿った設計が組めます。
- ユーザー文脈の保持:サービスアカウントに丸めず、「元々誰の依頼か」を保ったまま呼び出しを連鎖できます。
02標準(V2)とレガシー(V1)は別物
ここが最大の注意点です。Keycloakには歴史的に2つのToken Exchange実装が併存しており、挙動もサポート状態も異なります。長年テクノロジープレビューだったV1に対し、コミュニティと顧客からの強い要望を受けて標準実装(V2)が整備され、内部→内部のユースケースが正式サポートとして切り出されました(経緯はkeycloak/keycloak#31546で追えます)。
- 標準トークン交換 V2:Token exchange仕様(RFC 8693)に準拠。サーバー起動時にデフォルトで有効。フルサポート。ただし対応するのは「同一レルム内の内部→内部」交換に絞られます。
- レガシートークン交換 V1:4つのユースケース(内部→内部、内部→外部、外部→内部、impersonation)をカバーしますが、プレビュー扱いかつ非推奨(deprecated)の位置づけです。機能フラグでの明示的な有効化が必要です。
つまり「Keycloakのブログや古い記事で見たToken Exchangeの多彩な使い方」の大半はV1の話であり、V2では現時点で内部→内部に限られます。設計時にどちらを前提にしているかを取り違えると、実装フェーズで「その機能はプレビューです」となりかねません。
03V2のリクエストとパラメータ
V2の交換リクエストはtokenエンドポイントに対して行います。grant_typeには urn:ietf:params:oauth:grant-type:token-exchange を指定します。主要なパラメータは次のとおりです。
- grant_type(必須):上記のURN。
- subject_token(必須):交換元のトークン。V2で受け付ける subject_token_type は
urn:ietf:params:oauth:token-type:access_tokenのみです。 - requested_token_type(任意):既定はaccess_token。refresh_tokenやid_tokenも指定可能です。
- audience(任意):交換後トークンの宛先クライアントを指定します。複数指定も可能です。
- scope(任意):スペース区切りのスコープ。
重要な前提として、交換リクエストを送るクライアントは confidential である必要があり、public クライアントからのToken Exchangeはサポートされません。加えて、そのクライアントの設定で「Standard token exchange」を有効化するトグルをオンにする必要があります。デフォルトで機能自体は有効でも、クライアント単位の許可は明示が必要、という二段構えです。
aud クレームに、交換を要求するクライアント自身が含まれている必要があります。呼び出し元が自分宛でないトークンを持ち込んで交換しようとすると弾かれます。クライアントスコープやaudience mapperの設計と合わせて確認しておくと、実装時の「なぜ400が返るのか」を減らせます。
04audienceは「増やす」ではなく「絞る」
V2で最も誤解されやすいのがaudienceパラメータの役割です。V1のクライアント間交換では宛先を切り替える意味合いが強かったのに対し、V2のaudienceは、使用するクライアントスコープから生成されるaudienceを「絞り込む(フィルタする)」ためのものです。つまりaudienceを渡しても、そのクライアントスコープの設定上そもそも生成され得ないaudienceを新たに付与することはできません。
この挙動は実運用で効いてきます。たとえば「clientBに絞りたい」とaudienceを指定しても、交換元の文脈でclientB向けのaudienceが生成される設定になっていなければ、エラーが返ります(この点はコミュニティでも議論されています。keycloak/keycloak Discussion #40870)。設計上は、まず該当クライアントのクライアントスコープとaudience mapperで「どのaudienceが出得るか」を定義し、Token Exchangeのaudienceパラメータはその集合を実行時に狭める用途、と切り分けるのが正解です。
この「絞る方向でしか効かない」性質は、実は最小権限の観点では望ましい設計です。呼び出し側が勝手に宛先を広げられない、という保証になるからです。ロールやスコープの整理そのものは、クライアントスコープとProtocol Mapperやきめ細かな認可(Fine-grained Authz)の設計と地続きで考えると全体像が掴めます。
05impersonationとその線引き
「あるユーザーになりすまして下流を呼ぶ」impersonationは、運用サポートや管理代行のユースケースで求められがちです。ただしKeycloakにおいて、標準的なユーザーimpersonationを含む多彩な交換パターンはレガシーV1側の機能である点に注意が必要です。V1は前述のとおりプレビューかつ非推奨であり、フルサポートを前提としたエンタープライズ導入では扱いを慎重にすべきです。
- V1のimpersonationは
requested_subjectといったパラメータで対象ユーザーを指定する形で、管理系のきめ細かな権限(admin fine-grained authz)と組み合わせて誰が誰になりすませるかを制御します。 - V2は現時点で内部→内部に絞られており、いわゆる任意ユーザーへのimpersonationはスコープ外です。将来的な機能拡張の対象ではありますが、採用時は公式のToken Exchangeドキュメントで現行バージョンのサポート範囲を必ず確認してください。
06機能フラグとバージョン差の扱い
Quarkus版Keycloakでは、機能の有効化は --features オプションで行います。V2の標準トークン交換はデフォルトで有効なため、通常は追加のフラグ指定なしで使えます。一方、レガシーV1を使う場合は --features=token-exchange のような明示的な有効化(プレビュー機能群)が必要になります。プレビュー機能はサポート契約の対象外となる場合があるため、本番採用の可否は慎重に判断してください。
- ビルド時 vs 実行時:
--featuresはビルド時オプションに分類されるため、変更後は再ビルド(kc.sh build)が必要です。この境界の勘所はビルド時設定と実行時設定の分離で整理しています。 - WildFly版は非推奨:現行はQuarkus版が標準です。ネット上のToken Exchange設定手順にはWildFly版時代のものが混在するため、フラグ名やエンドポイントの前提バージョンを必ず確認してください(移行の観点はQuarkus版への移行を参照)。
なお、より新しいバージョンでは、外部発行のJWTを持ち込んでKeycloakのアクセストークンを得るJWT Authorization Grant(RFC 7523)と、Token Exchange(RFC 8693)を組み合わせたドメイン跨ぎのIdentity Chainingのプレビューも進んでいます(Keycloak公式ブログ)。分散システムやAIエージェントのように、複数の信頼境界をまたいで「誰の依頼か」を保持したいユースケースを見据えた動きで、ロードマップ上はこれらの正式サポート化とV1の非推奨化が並行しています。
07使いどころと注意点
V2を前提とした場合、Token Exchangeが素直にはまるのは次のような場面です。
- 同一レルム内のサービス連鎖:API Gatewayやフロントサービスが、ユーザー文脈を保ったまま下流サービス向けにaudienceを付け替える。最小権限を交換のたびに徹底できます。
- audienceの厳格化:各リソースサーバーが「自分宛のトークンだけ」を検証する構成に寄せられ、audience検証を緩める妥協を避けられます。
一方で、設計・実装時に踏みやすい注意点も明確です。
- subject_token_typeはaccess_tokenのみ(V2)。IDトークンやJWTを交換元にしたい要件はV2のスコープ外です。
- Sender-constrainedトークンの制約:DPoPバインドや証明書バインドのトークンはsubject_tokenとして使えません。相互TLSやDPoPを前提とした設計と併用する場合は動線を分けて考える必要があります。
- 委譲(delegation)・resourceパラメータ非対応:RFC 8693のactor/delegationセマンティクスやresourceパラメータはV2では扱えません。
- アクセストークンの失効チェーンがない:交換で発行したアクセストークンには失効の連鎖がありません(refresh_tokenには失効の仕組みがあります)。長寿命トークンを配りすぎない設計が前提です。
これらは制約というより「V2が内部→内部という限定された安全な領域に絞って正式サポートされている」ことの裏返しです。要件がこの枠に収まるならV2で堅く組み、外れる部分はアーキテクチャ側(トークンの寿命短縮、mTLSの別動線、必要最小限のV1利用の是非)で吸収するのが現実的です。Keycloakを用いた認証基盤の実装事例は導入事例でも紹介しています。
—まとめ
KeycloakのToken Exchangeは、RFC 8693に沿った内部→内部の権限委譲を正式機能(V2)として提供します。ポイントは、(1)V2とレガシーV1は別物でサポート状態も対応範囲も違う、(2)audienceは増やす方向ではなく絞る方向に効く、(3)impersonationや外部トークン交換は主にV1側の領域でプレビュー扱い、(4)機能フラグはビルド時オプションでバージョン前提の確認が必須、の4点です。要件をV2の枠に収められるかをまず見極め、収まらない部分は寿命管理や別プロトコルで補う。この切り分けができれば、Token Exchangeはマイクロサービスの認証設計を素直に締める強力な道具になります。
—参考(一次情報)
- Configuring and using token exchange — Keycloak公式ドキュメント
- token-exchange.adoc — Keycloak GitHub(ドキュメント原本)
- Support for standard Token-Exchange — keycloak/keycloak #31546
- Standard Token Exchange - Requested Audience not available — Discussion #40870
- JWT Authorization Grant and Identity Chaining in Keycloak 26.5 — Keycloak公式ブログ