跳至主要內容

MCP OBO 驗證

OAuth 2.0 On-Behalf-Of(OBO)驗證讓 LiteLLM 可將使用者傳入的 bearer token 交換為一個具範圍限制的 token,且該 token 對特定 MCP server 有效。

在以下情況使用 OBO:

  • 您的 MCP 伺服器應該接收一個專門為該 MCP 伺服器簽發的權杖。
  • 您的身分提供者支援 RFC 8693 OAuth 2.0 權杖交換,或是 Microsoft Entra ID,而 LiteLLM 原生支援它(請參閱下方的 Microsoft Entra ID)。
  • 您希望 LiteLLM 不要將使用者的原始權杖直接轉送到 MCP 伺服器。

運作方式​

簡單來說:

  1. 用戶端以 bearer token 向 LiteLLM 發送請求。
  2. LiteLLM 將該 bearer token 作為 RFC 8693 subject_token。
  3. LiteLLM 在您的身分識別提供者的 token exchange endpoint 進行交換。
  4. LiteLLM 只將交換後、具範圍限制的 token 轉送給 MCP server。
  5. LiteLLM 會快取交換後的 token 直到其過期,因此重複呼叫可避免再次往返身分識別提供者。

將 MCP Server 設定為 OBO​

在 MCP server 上設定 auth_type: oauth2_token_exchange。

config.yaml
mcp_servers:
internal_tools:
url: "https://mcp.example.com/mcp"
transport: "http"
auth_type: oauth2_token_exchange

# OAuth 2.0 Token Exchange endpoint on your identity provider
token_exchange_endpoint: "https://idp.example.com/oauth2/token"

# Token exchange client registered with your identity provider
client_id: "<idp-client-id>"
client_secret: "<idp-client-secret>"

# Optional but recommended: restrict the exchanged token to this MCP server
audience: "api://internal-tools-mcp"
scopes:
- "mcp.tools.read"
- "mcp.tools.execute"

# Optional. Defaults to access_token.
subject_token_type: "urn:ietf:params:oauth:token-type:access_token"

設定欄位​

欄位必要說明
auth_type是必須是 oauth2_token_exchange。
token_exchange_endpoint是接受 RFC 8693 權杖交換請求的身分提供者端點。
client_id是LiteLLM 在呼叫權杖交換端點時使用的 OAuth 用戶端識別碼。
client_secret是LiteLLM 在呼叫權杖交換端點時使用的 OAuth 用戶端密鑰。
audience建議MCP 伺服器的資源識別碼。LiteLLM 會將其作為權杖交換 audience 傳送。
scopes選用LiteLLM 為交換後的權杖請求的範圍。LiteLLM 會將清單連接成 OAuth scope 參數。
subject_token_type選用RFC 8693 subject token type。預設為 urn:ietf:params:oauth:token-type:access_token。
upstream_token_header選用上游哪個標頭承載交換後的權杖。預設為 Authorization。請參閱 將權杖傳送到不同的標頭。
token_exchange_profile選用交換的線路協定。rfc8693(預設)使用標準的 token-exchange grant;entra_obo 使用 Microsoft Entra ID 的 On-Behalf-Of flow。請參閱 Microsoft Entra ID。

將交換後的權杖傳送到不同的標頭​

預設情況下,交換後的權杖會以 Authorization: Bearer <token> 傳出。當 MCP 伺服器位於會從私有標頭讀取自身憑證的 API 閘道後方,而閘道後方的伺服器仍然期望在 Authorization 上收到自己的 bearer 時,這兩個憑證都必須走同一個請求。

將 upstream_token_header 設定為交換後的權杖應使用的標頭名稱。之後 static_headers 之下的內容都會保持不變,因此共用憑證仍可送達閘道後方的伺服器。

config.yaml
mcp_servers:
my_mcp_server:
url: "https://gateway.example.com/mcp"
auth_type: oauth2_token_exchange
token_exchange_endpoint: "https://idp.example.com/token"
client_id: os.environ/MCP_CLIENT_ID
client_secret: os.environ/MCP_CLIENT_SECRET
audience: "api://esb"
upstream_token_header: "esb-oauth"
static_headers:
Authorization: "Bearer os.environ/UPSTREAM_MCP_TOKEN"

接著每個上游請求都會同時帶上兩者,而交換後的權杖會限定於呼叫的使用者:

esb-oauth: Bearer <token exchanged for this user>
Authorization: Bearer <the shared token you configured>

交換後的權杖仍會依使用者快取,因此短效權杖不代表每個請求都要交換。將 upstream_token_header 保持未設定可維持預設行為。

如果上游的重新導向跨越來源,客製化標頭會被捨棄而不會被轉送,這與 HTTP 用戶端捨棄 Authorization 的方式相同。合法跨來源重新導向的上游將不會在第二次跳轉時看到該憑證。

Token Exchange 請求​

對於每個未快取的 subject token 與 MCP server 組合,LiteLLM 會向 token_exchange_endpoint 發送如下的 form-encoded 請求:

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<caller-bearer-token>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&client_id=<idp-client-id>
&client_secret=<idp-client-secret>
&audience=api://internal-tools-mcp
&scope=mcp.tools.read mcp.tools.execute

您的身分識別提供者應回傳一個 access token:

{
"access_token": "scoped-token-for-mcp-server",
"token_type": "Bearer",
"expires_in": 3600
}

接著 LiteLLM 會使用以下方式呼叫 MCP server:

Authorization: Bearer scoped-token-for-mcp-server

Microsoft Entra ID (Azure AD)​

Microsoft Entra ID 不實作上方的 RFC 8693 權杖交換授權。其 On-Behalf-Of flow 改用 RFC 7523 jwt-bearer 授權:呼叫端的權杖以 assertion 而非 subject_token 的形式傳入,沒有 audience 參數,而是由僅限 Microsoft 的 requested_token_use=on_behalf_of 擴充將該授權轉換為委派,而不是單純的 jwt-bearer 交換。LiteLLM 將 Entra 視為第一級設定檔,因此指向 Entra 是設定變更,而不是不同的整合:設定 token_exchange_profile: entra_obo,LiteLLM 就會建立 jwt-bearer 格式而非 RFC 8693 格式。

config.yaml
mcp_servers:
internal_tools:
url: "https://mcp.example.com/mcp"
transport: "http"
auth_type: oauth2_token_exchange
token_exchange_profile: entra_obo

# Your Entra tenant's v2.0 token endpoint
token_exchange_endpoint: "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token"

# App registration LiteLLM uses to call the token endpoint. The caller's
# token must have been issued with this client_id as its `aud`.
client_id: "<entra-app-client-id>"
client_secret: "<entra-app-client-secret>"

# Entra has no audience parameter, so the target resource goes in scope
# as <app-id-uri>/.default
scopes:
- "api://internal-tools-mcp/.default"

audience 和 subject_token_type 在 entra_obo 中不使用:Entra 沒有 audience 參數(目標資源會改放在 scope 中),而 jwt-bearer 授權不會檢查 subject token type。

對於每一組未快取的呼叫端權杖與 MCP 伺服器配對,LiteLLM 會傳送:

POST /<tenant-id>/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=<caller-bearer-token>
&scope=api://internal-tools-mcp/.default
&requested_token_use=on_behalf_of
&client_id=<entra-app-client-id>
&client_secret=<entra-app-client-secret>

Entra 回傳與上方相同的存取權杖回應格式,而 LiteLLM 會以相同方式快取並轉送交換後的權杖,不論設定檔為何。

備註

呼叫端的權杖必須是為 LiteLLM 的應用程式註冊所簽發,而不是其他 Entra 應用程式。如果您的測試工具是向不同的應用程式註冊進行驗證,請先讓它為此應用程式的範圍請求一個權杖,然後再將該權杖傳送給 LiteLLM。

呼叫 OBO MCP Server​

傳入請求必須包含使用者的 bearer token,讓 LiteLLM 有可供交換的 subject_token。

對於直接 MCP 呼叫,請將 LiteLLM key 保留在 x-litellm-api-key 中,並將 Authorization 留給使用者 token:

Direct MCP call
curl -X POST "https://litellm.example.com/internal_tools/mcp" \
-H "Content-Type: application/json" \
-H "x-litellm-api-key: Bearer <litellm-api-key>" \
-H "Authorization: Bearer <user-token>" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

對於 Responses API,請將 MCP tool headers 與 LiteLLM key 分開,並與使用者 token 分離傳遞:

Responses API with MCP OBO
curl -X POST "https://litellm.example.com/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <litellm-api-key>" \
-d '{
"model": "gpt-5.6-terra",
"input": "List the available internal tools",
"tools": [
{
"type": "mcp",
"server_label": "internal_tools",
"server_url": "https://litellm.example.com/internal_tools/mcp",
"require_approval": "never",
"headers": {
"x-litellm-api-key": "Bearer <litellm-api-key>",
"Authorization": "Bearer <user-token>"
}
}
]
}'
提示

如果 MCP client 只能傳送一個 Authorization header,請將 LiteLLM key 放在 x-litellm-api-key,並將 Authorization 保留給使用者的 token。LiteLLM 需要使用者 token 作為 OBO subject_token。

快取行為​

LiteLLM 會依下列條件快取交換後的 tokens:

  • subject token
  • MCP server ID

這表示兩個不同的使用者會取得各自獨立的交換後 tokens,而同一位使用者對同一個 MCP server 的重複呼叫,會重用快取的 token,直到其過期。

快取 TTL 以 expires_in 減去 LiteLLM 的 OAuth 到期緩衝區為基準。若 expires_in 遺失或無效,LiteLLM 會使用預設的 OAuth token cache TTL。

沒有 Subject Token 的請求​

如果對 oauth2_token_exchange 伺服器的請求沒有使用者 bearer 權杖,LiteLLM 會以 401 Unauthorized 和 WWW-Authenticate: Bearer resource_metadata="/.well-known/oauth-protected-resource/mcp/<server_name>", error="invalid_token", error_description="Missing or invalid subject token; authenticate with the IdP and retry" 拒絕它。不會退回到 OAuth client_credentials,而且在沒有交換後權杖的情況下,該請求絕不會被轉送到 MCP 伺服器。

如果您也需要對同一個 MCP 伺服器進行機器對機器存取,請另外註冊一個伺服器項目,並設定 auth_type: oauth2 和 client_id、client_secret 與 token_url。在該項目上設定 oauth2_flow: client_credentials;該代理程式會拒絕在沒有明確 oauth2_flow 的情況下啟動 oauth2 伺服器。

疑難排解​

症狀檢查
MCP server 收到 LiteLLM key將 LiteLLM key 移至 x-litellm-api-key,並使用 Authorization 作為使用者 token。
Token exchange endpoint 回傳 400確認 audience、scopes、client_id 和 subject_token_type 與您的身分識別提供者設定相符。
MCP server 沒有收到 Authorization header確認 MCP server 已設定 auth_type: oauth2_token_exchange,且傳入請求包含使用者 bearer token。
身分識別提供者在每個請求都被呼叫確認身分識別提供者回傳 expires_in,且正在重用相同的使用者 token 與 MCP server。