マイクロサービス間でユーザーの権限を安全に引き回す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向けのトークンへ交換する「内部→内部」の権限委譲です。

現場のコツ:Token Exchangeは「トークンを転送する」代替ではなく「トークンを作り直す」仕組みだと捉えると設計がぶれません。転送は検証を緩める方向、交換は検証を厳格化する方向に効きます。

02標準(V2)とレガシー(V1)は別物

ここが最大の注意点です。Keycloakには歴史的に2つのToken Exchange実装が併存しており、挙動もサポート状態も異なります。長年テクノロジープレビューだったV1に対し、コミュニティと顧客からの強い要望を受けて標準実装(V2)が整備され、内部→内部のユースケースが正式サポートとして切り出されました(経緯はkeycloak/keycloak#31546で追えます)。

つまり「Keycloakのブログや古い記事で見たToken Exchangeの多彩な使い方」の大半はV1の話であり、V2では現時点で内部→内部に限られます。設計時にどちらを前提にしているかを取り違えると、実装フェーズで「その機能はプレビューです」となりかねません。

図:内部→内部のToken Exchange(V2) サービスA (confidential) Keycloak token endpoint exchange サービスB (audience=B) 1. 手元token 2. B向けtoken 3. B向けtokenでBを呼び出し(Bは自分宛audienceだけ検証) 交換リクエストの要点 grant_type = urn:ietf:params:oauth:grant-type:token-exchange subject_token = 手元のaccess_token / audience = B
図:同一レルム内でAのトークンをB向けトークンに交換し、Bは自分宛のaudienceだけを検証する。

03V2のリクエストとパラメータ

V2の交換リクエストはtokenエンドポイントに対して行います。grant_typeには urn:ietf:params:oauth:grant-type:token-exchange を指定します。主要なパラメータは次のとおりです。

重要な前提として、交換リクエストを送るクライアントは confidential である必要があり、public クライアントからのToken Exchangeはサポートされません。加えて、そのクライアントの設定で「Standard token exchange」を有効化するトグルをオンにする必要があります。デフォルトで機能自体は有効でも、クライアント単位の許可は明示が必要、という二段構えです。

現場のコツ:V2では、subject_tokenの 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は前述のとおりプレビューかつ非推奨であり、フルサポートを前提としたエンタープライズ導入では扱いを慎重にすべきです。

現場のコツ:impersonationを要件に含める場合、「本当にユーザーになりすます必要があるのか」を一度立ち止まって問い直すと設計が締まります。多くのケースは、ユーザー文脈を保持したまま権限を絞る内部→内部の交換(V2)で足り、なりすまし特権を持つ経路を新設せずに済みます。

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はマイクロサービスの認証設計を素直に締める強力な道具になります。

参考(一次情報)

認証基盤におけるToken Exchangeの設計・実装でお困りの際は、Keycloak実構築の実績を持つお問い合わせまでご相談ください。

相談する
← ブログ一覧へ戻る