On-Behalf-Of (OBO) トークン交換 (RFC 8693 ) を使用すると、中間層サービスがダウンストリーム API を呼び出す際に、ユーザーの ID と権限を維持できます。
アプリケーションがダウンストリーム API を呼び出す必要がある場合は、次の方法を使用できます。
Client Credentials Flow : アプリケーションは自分自身のために動作し、自身として認証されます。リクエストがユーザーによって開始された場合でも、そのコンテキストは失われます。ダウンストリームサービスが認識できるのは、呼び出し元アプリケーションの ID のみです。
On-Behalf-Of (OBO) トークン交換: アプリケーションはユーザーに紐づくスコープを持つトークンを受け取り、それを新しいトークンに交換してダウンストリームサービスを呼び出せます。これにより、元のエンドユーザーの ID とコンテキストが呼び出しチェーン全体を通して維持されます。
たとえば、ユーザーが Service A の呼び出しをトリガーし、その後 Service A が Service B を呼び出す場合、OBO トークン交換を使うと、Service A はユーザーのアクセストークンを次のような新しいトークンに交換できます。
元のユーザーの ID と権限を維持する
Service B 向けに限定されたスコープを持つ
Service B がエンドユーザーに基づいて認可を判断できるようにする
OBO トークン交換では post-login Action trigger がトリガーされ、次のようになります。
標準的なログインフローと同様に、ダウンストリーム API 呼び出しで返されるスコープは、ユーザーの ロールベースアクセス制御 (RBAC) ポリシーに基づきます。
Auth0 for AI Agents アドオンを購入すると、OBO トークン交換では、ご利用のサブスクリプションティアにおける Authentication API の最大レート制限を利用できます。たとえば、Private Cloud 100 RPS を利用している場合、30 RPS の OBO トークン交換のレート制限を超えて、OBO トークン交換リクエストに 100 RPS の全容量を使用できます。Authentication API の上限は共有されており、ログイン、トークンのリフレッシュ、トークン交換を含むすべての Authentication API リクエストを合算した全体の上限として機能します。詳細については、テクニカルアカウントマネージャーにお問い合わせください。
OBO Token Exchange の一般的なユースケースには、次のようなものがあります。
ユーザーの代わりにファーストパーティ API を呼び出す必要がある MCP サーバー
ユーザーの代わりにダウンストリームサービスを呼び出す必要があるマイクロサービス
アプリケーションからユーザーの代わりにサードパーティ API を呼び出せるようにするには、Token Vault を使用します。
OBO トークン交換では、中間層サービスが受信したユーザー トークンを、ダウンストリーム サービス向けのスコープを持つ新しいトークンに交換できます。この新しいトークンは、元のユーザーの識別情報を保持したまま、JSON Web Token (JWT) ペイロード内で経由したサービスの連鎖を追跡します。
例: MCP サーバーがファーストパーティ API を呼び出す
ユーザーが Auth0 を使用してクライアントアプリケーションに認証され、その後そのアプリケーションが MCP サーバーを呼び出し、さらに MCP サーバーがファーストパーティ API を呼び出す必要があります。
ユーザーがログインすると、Auth0 は JWT ペイロードに次のクレームを含む、MCP サーバー用のスコープが付与されたアクセストークンを発行します。
{
"sub" : "auth0|user123" ,
"aud" : "https://mcp-server.example.com" ,
"azp" : "spa_client_id" // トークンのプロファイルによって "client_id" になる場合もある
}
クレーム 値 説明 subauth0|user123エンドユーザーのID audhttps://mcp-server.example.comMCP サーバー向けのスコープが設定されたトークン azp (or client_id depending on the アクセストークンプロファイル )spa_client_idトークンを要求したクライアントアプリケーション
OBO トークン交換を使用すると、MCP サーバーはユーザーのトークンを Auth0 に提示し、ファーストパーティ API 用のスコープが付与されたアクセストークンを要求します。Auth0 は、次のクレームを含む、その API 用にスコープが付与された新しいアクセストークンを発行します。
{
"sub" : "auth0|user123" ,
"aud" : "https://first-party-api.example.com" ,
"azp" : "mcp_server_client_id" , // またはトークンプロファイルによっては "client_id"
"act" : {
"sub" : "mcp_server_client_id" ,
"act" : {
"sub" : "spa_client_id"
}
}
}
クレーム 値 説明 subauth0|user123同一のユーザー ID が維持される audhttps://first-party-api.example.comファーストパーティ API を対象とするトークン azp (or client_id depending on the アクセストークンプロファイル )mcp_server_client_idトークンを要求したクライアント (トークン交換を実行した MCP サーバー) act{"sub": "mcp_server_client_id","act": {"sub": "spa_client_id"}}関与したすべてのアクターを示す委任チェーン
act (actor) クレームは、委任チェーン全体を追跡します。各 act レベルはコールチェーン内のサービスを表し、最も外側の act.sub は、現在のアクター、つまりトークン交換を実行した主体を識別します。
この例では、次のとおりです。
最も外側の act.sub: mcp_server_client_id (直前にトークン交換を行った MCP サーバー)
ネストされた act.sub: spa_client_id (元のクライアントアプリケーション)
azp クレームは最も外側の act.sub の値と一致し、直近でトークン交換を行ったサービスを識別している必要があります。
ファーストパーティ API が別のダウンストリームサービス (https://calendar-api.acme.com) を呼び出す場合、委任チェーンはさらに拡張されます。
{
"sub" : "auth0|user123" ,
"aud" : "https://calendar-api.acme.com" ,
"azp" : "first_party_api_client_id" ,
"act" : {
"sub" : "first_party_api_client_id" ,
"act" : {
"sub" : "mcp_server_client_id" ,
"act" : {
"sub" : "spa_client_id"
}
}
}
}
委任チェーンは、ネストされた階層を 5 レベルまでに制限しています。サブジェクトトークンにすでに 5 つの act ネストレベルがある場合、OBO トークン交換は失敗します。
400 Bad Request
{
"error" : "invalid_request" ,
"error_description" : "Delegation chain (`act` claim) depth exceeds the maximum allowed limit of 4"
}
API 呼び出しのたびに新しいトークンを要求するのではなく、アクセストークンはトークンの有効期間中キャッシュしてください。アクセストークンは有効期限が切れるまで再利用できます。トークンの取得を繰り返すと、リソースを無駄にし、レイテンシが増加し、レート制限に達する可能性があります。
ユーザー > MCP サーバー > API フロー
次の図は、MCP サーバー がユーザーに代わってファーストパーティ API を呼び出す際の、エンドツーエンドの OBO トークン交換フローを示しています。
ユーザー認証 : ユーザーはクライアントアプリケーションで認証されます。Auth0 認可サーバーは、MCP サーバー向けのスコープを持つトークン A を発行します。
初回リクエスト : クライアントアプリケーションは MCP サーバーを呼び出し、Authorization: Bearer ヘッダーでトークン A を渡します。
検証とトークン交換 : MCP サーバーはトークン A を受信して検証し、その後 Auth0 認可サーバーの /oauth/token エンドポイントに渡します。OBO トークン交換を使用して、MCP サーバーはトークン A を subject_token として提示し、ファーストパーティ API 用の新しいトークンを要求します。
トークン発行 : Auth0 認可サーバーはトークン B を発行します。トークン B の sub (ユーザー ID) はトークン A と同じですが、aud (オーディエンス) はファーストパーティ API になります。
ダウンストリーム呼び出し : MCP サーバーはトークン B を使用してファーストパーティ API を呼び出します。API はトークン B を検証し、そのリクエストが元のユーザーに代わって正当に行われていることを確認します。
ユーザー > API1 > API2 > API3
次の図は、マイクロサービスの連鎖がユーザーに代わって下流のサービスを呼び出すエンドツーエンドのフローを示しています。
ユーザー認証 : ユーザーはクライアントアプリケーションに正常に認証されます。Auth0 認可サーバーは、API1 向けのスコープを持つ Token A を発行します。
初回リクエスト : クライアントアプリケーションは API1 を呼び出し、Authorization: Bearer ヘッダーで Token A を渡します。
API1 から API2 への委任 : API1 は Token A を受け取って検証した後、Auth0 認可サーバーの /oauth/token エンドポイントに送信します。OBO トークン交換を使用して、API1 は Token A を subject_token として提示し、API2 用の新しいトークンを要求します。
トークンの発行 : Auth0 認可サーバーは API1 に新しいアクセストークン Token B を付与します。Token B の sub (ユーザー ID) は Token A と同じですが、aud (オーディエンス) は API2 になります。
ダウンストリーム呼び出し : API1 は Token B を使用して API2 にリクエストを送信します。
API2 から API3 への委任 : API2 は Token B を受け取って検証した後、Auth0 認可サーバーの /oauth/token エンドポイントに送信します。OBO トークン交換を使用して、API2 は Token B を subject_token として提示し、API3 用の新しいトークンを要求します。
トークンの発行 : Auth0 認可サーバーは API2 に新しいアクセストークン Token C を付与します。Token C の sub (ユーザー ID) は Token A および Token B と同じですが、aud (オーディエンス) は API3 になります。
ダウンストリーム呼び出し : API2 は Token C を使用して API3 にリクエストを送信します。API3 は Token C を検証し、そのリクエストが元のユーザーに代わって正当に行われていることを確認します。
OBO トークン交換を使用できるのは、リソースサーバーに関連付けられた Custom API クライアントのみです。Custom API クライアントは、リソースサーバーと同じ識別子を共有している場合、そのリソースサーバーに関連付けられます。
Custom API クライアントには、次の要件があります。
app_type を resource_server に設定します。
resource_server_identifier を有効なリソースサーバー、つまり https://my-api.example.com に設定します。Auth0 は、認可リクエストでリソースサーバー識別子を audience パラメーターとして使用します。
Custom API クライアントはファーストパーティ クライアントであるため、ファーストパーティ クライアントがアクセスする必要がある API については、必ずユーザーの同意をスキップ してください。
Auth0 Dashboard または Management API を使用して、Custom API クライアントを作成できます。
Auth0 Dashboard
Management API
Auth0 Dashboard で Custom API クライアントを作成するには、次の手順に従います。
Applications > APIs に移動し、バックエンド API を選択します。
Add Application を選択し、アプリケーション名を入力します。
Add を選択します。
アプリケーションが正常に作成されたら、Configure Application を選択して確認し、Application Properties までスクロールします。Application Type は Custom API Client です。 リソースサーバーと同じ識別子を持つ Custom API クライアントを作成するには、次のリクエストボディを指定して /api/v2/clients エンドポイントに POST リクエストを送信します。 curl --request POST 'https://{yourDomain}/api/v2/clients' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_MANAGEMENT_API_TOKEN' \
--data '{
"name": "Custom API Client",
"app_type": "resource_server",
"resource_server_identifier": "https://my-api.example.com"
}'
パラメーター 説明 nameCustom API クライアントの名前です。 app_typeCustom API クライアントのアプリケーションタイプです。resource_server に設定します。 resource_server_identifierCustom API クライアントの一意の識別子です。リソースサーバーのオーディエンス、つまり https://my-api.example.com に設定します。
アクセスを認可するには、Custom API クライアントとダウンストリーム API の間に、ユーザー委任のクライアントグラントを作成する必要があります。
Auth0 Dashboard
Management API
Applications > Applications に移動し、Custom API クライアントを選択します。
API Access で、対象のリソースサーバー (例: https://my-api.example.com) を見つけて Edit を選択します。
User-Delegated Access で Grant Access を選択し、付与する権限を選択するか、Always grant all permissions を選択します。
Save を選択します。
次のリクエストボディを指定して、/api/v2/client-grants エンドポイントに POST リクエストを送信します。 curl --location 'https://{yourDomain}/api/v2/client-grants' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_MANAGEMENT_API_TOKEN' \
--data '{
"client_id": "YOUR_CLIENT_ID",
"audience": "https://my-api.example.com",
"scope": [
"read:item"
],
"subject_type": "user"
}'
OBO トークン交換グラントを使用するように Custom API クライアントを設定する方法を説明します。
Auth0 Dashboard
Management API
Applications > Applications に移動し、Custom API クライアントを選択します。
Token Exchange で、On-Behalf-Of Token Exchange をオンにします。
Save を選択します。
次のリクエスト本文を使用して、/api/v2/clients/{clientId} エンドポイントに PATCH リクエストを送信します。 curl --location --request PATCH 'https://{yourDomain}/api/v2/clients/{clientId}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_MANAGEMENT_API_TOKEN' \
--data '{
"token_exchange": {
"allow_any_profile_of_type": ["on_behalf_of_token_exchange"]
}
}'
OBOトークン交換を実行するには、auth0-api-js 、auth0_api_python 、または Authentication API を使用できます。
API 呼び出しのたびに新しいトークンを要求するのではなく、アクセストークンはトークンの有効期間中キャッシュしてください。アクセストークンは有効期限が切れるまで再利用できます。トークン交換を繰り返すと、リソースの無駄遣いになり、レイテンシが増加し、レート制限に達する可能性があります。
始める前に、auth0-api-js ライブラリとその依存関係をインストールしておいてください。 まず、MCP サーバーの認証情報を使用して ApiClient を初期化します。 import { ApiClient } from '@auth0/auth0-api-js' ;
const apiClient = new ApiClient ({
domain: 'YOUR_AUTH0_DOMAIN' ,
audience: 'YOUR_MCP_SERVER_AUDIENCE' ,
clientId: 'YOUR_CLIENT_ID' ,
clientSecret: 'YOUR_CLIENT_SECRET' ,
});
次に、getTokenOnBehalfOf() メソッドを使用してトークン交換を行います。 const result = await apiClient . getTokenOnBehalfOf ( accessToken , {
audience: 'YOUR_DOWNSTREAM_API_AUDIENCE' ,
scope: 'read:private' , // 省略可能
});
getTokenOnBehalfOf() は、次を含むオブジェクトを返します。
accessToken: ダウンストリーム API 用の新しいトークン
scope: 付与されたスコープ
expiresIn: トークンの有効期間 (秒)
始める前に、auth0_api_python ライブラリとその依存関係をインストールしておいてください。 まず、必要なクラスをインポートし、MCP サーバーの認証情報を使用して ApiClient を初期化します。 from auth0_api_python import ApiClient, ApiClientOptions
api_client = ApiClient(
ApiClientOptions(
domain = 'YOUR_AUTH0_DOMAIN' ,
audience = 'YOUR_MCP_SERVER_AUDIENCE' ,
client_id = 'YOUR_CLIENT_ID' ,
client_secret = 'YOUR_CLIENT_SECRET' ,
)
)
次に、get_token_on_behalf_of() メソッドを使用してトークン交換を行います。 result = await api_client.get_token_on_behalf_of(
access_token = access_token,
audience = 'YOUR_DOWNSTREAM_API_AUDIENCE' ,
scope = 'read:private' # 省略可能
)
get_token_on_behalf_of() は、次を含む辞書を返します。
access_token: ダウンストリーム API の新しいトークン
scope: 付与されたスコープ
expires_in: トークンの有効期限 (秒単位)
次のリクエストボディを指定して、/oauth/token エンドポイントに POST リクエストを送信します。 curl --location 'https://YOUR_DOMAIN.us.auth0.com/oauth/token' \
--header 'Content-Type: application/json' \
--data '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"subject_token": "AUTH0_SUBJECT_TOKEN",
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
"requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
"audience": "https://my-api.example.com"
}'
Parameter Example Description grant_typeurn:ietf:params:oauth:grant-type:token-exchange必須。標準的なログインではなく、トークン交換を実行するよう認可サーバーに指示します。 client_id<custom_api_client_id>必須。リクエストを行う中間層サービスの固有 ID です。 client_secret<custom_api_client_secret>任意。中間層サービス自体を認証するために使用するシークレット (またはアサーション) です。任意のクライアント認証方式を使用できますが、token_endpoint_auth_method を none に設定することはできません。 subject_token<auth0_access_token>必須。中間層サービスが現在保持している、ユーザーまたはクライアントから受け取ったトークンです。 subject_token_typeurn:ietf:params:oauth:token-type:access_token必須。subject_token の形式を定義します (例: アクセストークンまたはIDトークン) 。 requested_token_typeurn:ietf:params:oauth:token-type:access_token必須。返されるトークンの種類を指定します (通常は次に呼び出す API 用のアクセストークン) 。 audiencehttps://my-api.example.com必須。新しいトークンを受け取り、検証するダウンストリームサービスの識別子です。 scoperead:data write:data任意。ダウンストリーム呼び出しに対して要求する特定の権限を、スペース区切りで並べたリストです。
成功すると、次のようなレスポンスが返されます。 {
"access_token" : "YOUR_AUTH0_ACCESS_TOKEN" ,
"expires_in" : 86400 ,
"token_type" : "Bearer" ,
"issued_token_type" : "urn:ietf:params:oauth:token-type:access_token"
}
パラメーター 例 説明 access_tokeneyJ...”新しい” Auth0 アクセストークンです。ミドルティアサービスがダウンストリーム API を呼び出す際に使用する JWT または不透明な文字列です。 issued_token_typeurn:ietf:params:oauth:token-type:access_token返されたトークンの形式を示します。これは、リクエストの requested_token_type と一致するか、そのサブセットになります。 token_typeBearerAuthorization ヘッダーで使用する認証スキームを指定します。OBO では、ミドルティアサービスとダウンストリーム API が DPoP を使用している場合を除き、Bearer になります。その場合は DPoP が使用されます。expires_in3600ダウンストリーム API の設定に応じた、トークンの有効期間 (秒単位) です。通常、これは元のユーザートークンより短くなります。 scoperead:dataそのトークンに付与される具体的な権限です。これらの権限を有効にするには、ユーザー委任アクセス クライアントグラント を設定する必要があります。
ユーザーが組織経由で認証されると、アクセストークンには org_id クレームが含まれます。OBO トークン交換では、この組織コンテキストが委任チェーン全体で維持されます。
Auth0 が組織に関連付けられたアクセストークンを含む OBO トークン交換リクエストを受信すると、次の点を検証します。
org_id がテナント内に存在すること
ユーザー (sub で識別される) がその組織のメンバーであること
検証に失敗した場合、Auth0 はトークン交換リクエストを拒否します。検証に成功すると、Auth0 は次のような新しいアクセストークンを発行します。