基於 JWT 的 OIDC 驗證
使用 JWT 來對閘道中的管理員 / 使用者 / 專案進行驗證。
想要每位使用者的模型限制、花費上限與速率限制,而不必分發 API 金鑰嗎?請參閱 JWT → Virtual Key Mapping,以了解適用於 JWT 驗證使用者的精細存取控制(例如 Claude Code + SSO)。
使用方式
步驟 1. 設定閘道
JWT_PUBLIC_KEY_URL:這是您 OpenID 提供者的公開金鑰端點。通常是{openid-provider-base-url}/.well-known/openid-configuration/jwks。對於 Keycloak,則是{keycloak_base_url}/realms/{your-realm}/protocol/openid-connect/certs。JWT_AUDIENCE:這是用於解碼 JWT 的受眾。如果未設定,解碼步驟將不會驗證受眾。
export JWT_PUBLIC_KEY_URL="" # "https://demo.duendesoftware.com/.well-known/openid-configuration/jwks"
- 在您的設定中加入
enable_jwt_auth。這會告訴閘道檢查某個權杖是否為 JWT 權杖。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
model_list:
- model_name: azure-gpt-3.5
litellm_params:
model: azure/<your-deployment-name>
api_base: os.environ/AZURE_API_BASE
api_key: os.environ/AZURE_API_KEY
api_version: "2023-07-01-preview"
步驟 2. 建立具 scope 的 JWT
- admin
- project
在您的 OpenID 提供者(例如 Keycloak)中建立名為 litellm_proxy_admin 的用戶端 scope。
在產生 JWT 時,授予您的使用者 litellm_proxy_admin scope。
curl --location ' 'https://demo.duendesoftware.com/connect/token'' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={CLIENT_ID}' \
--data-urlencode 'client_secret={CLIENT_SECRET}' \
--data-urlencode 'username=test-{USERNAME}' \
--data-urlencode 'password={USER_PASSWORD}' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'scope=litellm_proxy_admin' # 👈 grant this scope
在您的 OpenID 提供者(例如 Keycloak)中為您的專案建立 JWT。
# client_id: 👈 project id
curl --location ' 'https://demo.duendesoftware.com/connect/token'' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={CLIENT_ID}' \
--data-urlencode 'client_secret={CLIENT_SECRET}' \
--data-urlencode 'grant_type=client_credential' \
步驟 3. 測試您的 JWT
- /key/generate
- /chat/completions
curl --location '{proxy_base_url}/key/generate' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiI...' \
--header 'Content-Type: application/json' \
--data '{}'
curl --location 'http://0.0.0.0:4000/v1/chat/completions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1...' \
--data '{"model": "azure-gpt-3.5", "messages": [ { "role": "user", "content": "What's the weather like in Boston today?" } ]}'
進階
多個 OIDC 提供者
如果您希望 LiteLLM 根據多個 OIDC 提供者(例如 Google Cloud、GitHub Auth)驗證您的 JWT,請使用此功能。
在您的環境中設定 JWT_PUBLIC_KEY_URL,值為以逗號分隔的 OIDC 提供者 URL 清單。每個項目可以是 JWKS URL 或 OIDC discovery URL(.../.well-known/openid-configuration);LiteLLM 會擷取 discovery 文件並追蹤其 jwks_uri
export JWT_PUBLIC_KEY_URL="https://demo.duendesoftware.com/.well-known/openid-configuration,https://accounts.google.com/.well-known/openid-configuration"
這會以一組共用的 claim 對應,驗證來自每個列出提供者的 token。若您的提供者對某個給定 claim 的內容定義不同,請改用按 issuer 的 claim 對應
Token 如何驗證
LiteLLM 會從未驗證的 JWT 標頭讀取 kid,並依序走訪 JWT_PUBLIC_KEY_URL 清單。對每個 URL,它會載入該提供者的金鑰集合,並尋找其 kid 等於 token 的金鑰。第一個符合者會勝出,搜尋便在此停止;若沒有任何列出的提供者發布該 kid,請求會以 401(No matching public key found)被拒絕。此路徑中 iss claim 不參與金鑰集合的選擇,因此僅由 kid 決定要嘗試哪個提供者的金鑰
沒有 kid 標頭的 token,只有在金鑰集合恰好包含一把金鑰時才會符合。若 JWKS 中有多把金鑰,則會被拒絕,因此會輪替金鑰的提供者必須在標頭中放入 kid
選定金鑰後,會用它驗證簽章,並檢查 exp(若存在,另加 nbf 與 iat)。可接受的演算法為 RS256/384/512、PS256/384/512、ES256/384/512 與 EdDSA;以 HMAC 簽署的 token(HS*)一律會被拒絕。金鑰材料會從 JWK 的 kty、n、e、x、y 和 crv 成員讀取,因此 RSA、EC 與 OKP 金鑰都可使用,而 x5c 憑證鏈會被忽略
只有在您要求時,才會驗證 aud 和 iss。JWT_AUDIENCE 會設定預期的 audience(其 aud 為清單的 token,若包含該值則通過),而 JWT_ISSUER 會設定預期的 iss。兩者都是清單中每個 URL 共用的單一值,因此在有多個提供者時,JWT_ISSUER 只能接受其中之一;若設定需要為多個提供者驗證 iss,必須使用 per-issuer configuration。兩者都不設定時,任何由清單中任一提供者簽署的 token 都會被接受,不論它是為哪個應用程式簽發,而 proxy 會在首次使用時記錄警告說明此事
快取與失敗行為
每個金鑰集合(以及每個 discovery 文件)都會快取在 proxy 的驗證快取中;若已設定則使用 Redis,否則使用程序內記憶體,快取時間為 litellm_jwtauth.public_key_ttl 秒(預設 600)。kid miss 在 TTL 內不會觸發重新擷取,因此若 token 是由提供者剛輪替進去的金鑰簽署,會在快取副本過期前被拒絕
當擷取在傳輸層失敗(DNS、連線、TLS、逾時)時,LiteLLM 會以短暫退避最多重試三次,然後將該中斷狀態記住 30 秒,避免並發請求一窩蜂打到失效端點。若該金鑰集合存在最後一次已知正常的副本,且其時間新於 public_key_ttl + public_key_stale_ttl(預設 600 + 3600 秒),系統會提供該副本並記錄警告。否則請求會以 503(the identity provider's JWKS endpoint is temporarily unreachable)失敗,且不會嘗試清單中的其餘 URL,即使其中之一持有相符的金鑰。將 public_key_stale_ttl: 0 設為在快取副本過期時立即 fail closed。非 200 回應或無法解析的內容既不會重試,也不會提供過期副本;它會以 401 使請求失敗,並且停止清單遍歷
general_settings:
enable_jwt_auth: true
litellm_jwtauth:
public_key_ttl: 600
public_key_stale_ttl: 3600
按 issuer 的 claim 對應
當同一個 claim 會因為是哪個提供者簽發 token 而有不同意義時,請使用 litellm_jwtauth.issuers。常見情況是:一個提供者把 team ID 放在 sub,另一個則把 user ID 放在那裡,因此單一全域 team_id_jwt_field: "sub" 無法同時適用兩者
每個項目都會依據 token 的 iss claim 進行比對,並帶有各自的 JWKS URL、audience 與 claim 對應
general_settings:
enable_jwt_auth: true
litellm_jwtauth:
admin_jwt_scope: "litellm_proxy_admin"
issuers:
- issuer: "https://accounts.google.com"
audience: "my-gcp-audience"
team_id_jwt_field: "sub"
- issuer: "https://keycloak.example.com/realms/my-realm"
jwks_url: "https://keycloak.example.com/realms/my-realm/protocol/openid-connect/certs"
audience: "my-keycloak-audience"
user_id_jwt_field: "sub"
user_email_jwt_field: "email"
使用此設定時,來自 accounts.google.com 的 token 會將 sub 解析為 team ID,而來自 Keycloak 的 token 則會將相同的 sub 解析為 user ID
按 issuer 的欄位
| 欄位 | 必要 | 說明 |
|---|---|---|
issuer | 是 | 預期的 iss claim 值。比對時採用完全相同的字串比較 |
audience | 是,除非已設定 disable_audience_validation | 此 issuer 的 token 預期 aud |
disable_audience_validation | 是,除非已設定 audience | 對此 issuer 略過 audience 驗證。同時設定此項與 audience 會被拒絕 |
jwks_url | 否 | 此 issuer 的 JWKS 端點。預設為讀取 <issuer>/.well-known/openid-configuration 並追蹤其 jwks_uri |
team_id_jwt_field | 否 | 要讀取為 team ID 的 claim 路徑 |
team_ids_jwt_field | 否 | 要讀取為 team ID 清單的 claim 路徑 |
user_id_jwt_field | 否 | 要讀取為 user ID 的 claim 路徑 |
user_email_jwt_field | 否 | 要讀取為 user email 的 claim 路徑 |
org_id_jwt_field | 否 | 要讀取為 organization ID 的 claim 路徑 |
end_user_id_jwt_field | 否 | 要讀取為 end-user ID 的 claim 路徑 |
Claim 路徑支援巢狀 claim 的點記號表示法,例如 resource_access.my-client.team
需要知道的事項
每個 issuer 都必須設定 audience 或 disable_audience_validation: true 其中之一。否則 LiteLLM 會在啟動時拒絕此設定,因此由另一個與您的提供者共用簽署金鑰的應用程式所簽發的 token,無法向您的 proxy 驗證
您未在 issuer 項目中填寫的 claim 對應,會回退到頂層 litellm_jwtauth 設定。若您保留全域 team_id_jwt_field: "sub",並新增一個只對 user_id_jwt_field: "sub" 進行對應的 issuer,該 issuer 的 token 仍會從 sub 讀取 team ID。請將所有 claim 對應移入 issuers 以避免此情況
issuers 是加法式路由,而非 allow-list。其 iss 不符合任何項目的 token 會落回全域 JWT_PUBLIC_KEY_URL 與 JWT_AUDIENCE 路徑,因此若您只想接受列出的 issuers,請將這些設定留空
比對只針對 iss。kid 標頭仍會在相符 issuer 的 JWKS 內選擇簽署金鑰
建議的多提供者設定
若有多個提供者,即使 claim 對應相同,也建議使用 litellm_jwtauth.issuers,而非共用清單。issuers 項目會將金鑰查找範圍限定於該 issuer 自己的 JWKS,並逐一依提供者驗證 iss 與 aud,這是共用清單無法做到的。請將 JWT_PUBLIC_KEY_URL 保持未設定,讓其 iss 未列出的 token 被拒絕(401,Missing JWT Public Key URL),而不是落入未限定範圍的路徑。上述的金鑰快取與過期副本回退行為,會以相同方式套用到每個 issuer 的 JWKS
general_settings:
enable_jwt_auth: true
litellm_jwtauth:
user_id_jwt_field: "sub"
user_email_jwt_field: "email"
issuers:
- issuer: "https://keycloak.example.com/realms/my-realm"
audience: "litellm-proxy"
- issuer: "https://sts.example-cloud.com"
jwks_url: "https://sts.example-cloud.com/.well-known/jwks.json"
audience: "litellm-proxy"
提供者相容性
LiteLLM 不會針對任何身分提供者做特殊處理。只要某個簽發者使用上方列出的其中一種演算法簽署 token、以 JWKS 公開其公鑰(直接公開,或透過包含 jwks_uri 的 OIDC discovery 文件)、設定一個出現在該 JWKS 中的 kid 標頭,並且簽發一個穩定的 iss 值再加上您設定的 audience,就都可以正常運作。本頁展示的 Keycloak 與 Kubernetes 簽發者就是用這種方式公開金鑰;對於其他任何簽發者,請先用解碼後的範例 token 與該提供者的 JWKS 檢查這四點,再決定是否依賴它。
疑難排解
使用 --detailed_debug 執行 proxy,查看說明每個拒絕原因的 JWT Auth: 記錄行。
| 症狀 | 原因 | 修正 |
|---|---|---|
401 No matching public key found. keys=[...], kid=... | 列出的 JWKS 都不包含 token 的 kid,或 token 沒有 kid 而 JWKS 有多把金鑰 | 確認 token 標頭中的 kid 出現在其中一份 JWKS 文件中。如果提供者剛輪替金鑰,請等待 public_key_ttl,或重新啟動 proxy |
在 JWT_PUBLIC_KEY_URL 中有多個提供者時出現 401 Validation fails: Signature verification failed | 兩個提供者公開了相同的 kid;共享清單會挑選具有它的第一個 URL,並用錯誤的金鑰進行驗證 | 請使用 litellm_jwtauth.issuers,讓查找範圍限定在 token 的簽發者 |
401 Validation fails: Invalid issuer | iss 不等於 JWT_ISSUER(共享路徑),或不等於比對到的 issuers[].issuer | 請從解碼後的 token 原樣複製 iss;尾端斜線以及 http 與 https 都很重要 |
401 Validation fails: Audience doesn't match 或 Token is missing the "aud" claim | aud 不包含 JWT_AUDIENCE / issuers[].audience,或 token 沒有 aud | 設定您的提供者實際簽發的 audience(通常是 client ID),或在該簽發者無法簽發時設定 disable_audience_validation: true |
401 Validation fails: The specified alg value is not allowed | Token 是使用 HMAC 簽署,或使用了上方清單以外的演算法 | 將提供者設定為使用 RS256 或其他非對稱演算法簽署 |
401 OIDC discovery document at ... does not contain a 'jwks_uri' field | 該 URL 包含 .well-known/openid-configuration,因此被視為 discovery 文件,但它回傳的是 JWKS | 將 JWT_PUBLIC_KEY_URL 指向 discovery 文件本身,或指向路徑不包含該片段的 JWKS URL |
503 the identity provider's JWKS endpoint is temporarily unreachable | 無法連上 JWKS 或 discovery URL,且沒有可用的舊版快取 | 檢查 proxy 到提供者的對外連線。提高 public_key_stale_ttl 以撐過較長的中斷 |
401 Missing JWT Public Key URL from environment | iss 未匹配任何 issuers 項目,且未設定 JWT_PUBLIC_KEY_URL | 將該簽發者加入 issuers,或在應接受未列出簽發者時設定 JWT_PUBLIC_KEY_URL |
Kubernetes ServiceAccount 驗證
使用 Kubernetes ServiceAccount 權杖來驗證叢集中執行的工作負載。當您希望 pod 使用其原生 Kubernetes 身分向 LiteLLM 進行驗證時,這很有用。
先決條件
- 您的 Kubernetes 叢集必須啟用 ServiceAccount 權杖投影(Kubernetes 1.20+ 預設啟用)
- 您叢集的 OIDC issuer 必須可存取(對 EKS、GKE、AKS 而言這是自動的)
步驟 1:設定 OIDC Discovery URL
將 JWT_PUBLIC_KEY_URL 設定為您叢集的 OIDC discovery 端點:
- Amazon EKS
- Google GKE
- Azure AKS
- Self-Managed
# Get your EKS OIDC issuer URL
aws eks describe-cluster --name <cluster-name> --query "cluster.identity.oidc.issuer" --output text
# Set the JWKS URL (append /keys to the issuer URL)
export JWT_PUBLIC_KEY_URL="https://oidc.eks.<region>.amazonaws.com/id/<id>/keys"
# GKE uses Google's OIDC provider
export JWT_PUBLIC_KEY_URL="https://container.googleapis.com/v1/projects/<project>/locations/<location>/clusters/<cluster>/jwks"
# Get your AKS OIDC issuer URL
az aks show --name <cluster-name> --resource-group <resource-group> --query "oidcIssuerProfile.issuerUrl" -o tsv
# Set the JWKS URL
export JWT_PUBLIC_KEY_URL="<issuer-url>/openid/v1/jwks"
# For self-managed clusters, check your API server's --service-account-issuer flag
# The JWKS endpoint is typically at:
export JWT_PUBLIC_KEY_URL="https://<api-server>/openid/v1/jwks"
步驟 2:設定 LiteLLM
設定 LiteLLM 以從 Kubernetes ServiceAccount 權杖中擷取身分資訊:
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
# Use namespace as team identifier (resolves via team_alias in DB)
team_alias_jwt_field: 'kubernetes\.io.namespace'
步驟 3:建立 ServiceAccount 並設定 Pod
建立一個關聯秘密的 ServiceAccount,並將您的 pod 設定為使用該權杖:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-llm-client
namespace: my-app
---
apiVersion: v1
kind: Secret
metadata:
name: my-llm-client-token
namespace: my-app
annotations:
kubernetes.io/service-account.name: my-llm-client
type: kubernetes.io/service-account-token
---
apiVersion: v1
kind: Pod
metadata:
name: llm-client-pod
namespace: my-app
spec:
serviceAccountName: my-llm-client
containers:
- name: app
image: my-app:latest
env:
- name: LITELLM_TOKEN
valueFrom:
secretKeyRef:
name: my-llm-client-token
key: token
在 LiteLLM 中設定預期的受眾:
export JWT_AUDIENCE="https://kubernetes.default.svc"
步驟 4:為 Namespace 建立 Team
在 LiteLLM 中建立一個與 namespace 相符的 team(使用 team_alias):
curl -X POST 'http://0.0.0.0:4000/team/new' \
-H 'Authorization: Bearer <PROXY_MASTER_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"team_alias": "my-app",
"team_id": "my-app",
"models": ["gpt-5.6-terra", "claude-sonnet-5"]
}'
步驟 5:使用權杖
從 pod 內部,權杖可在 LITELLM_TOKEN 環境變數中取得:
# Make a request to LiteLLM using the env var
curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $LITELLM_TOKEN" \
-d '{
"model": "gpt-5.6-terra",
"messages": [{"role": "user", "content": "Hello!"}]
}'
範例:ServiceAccount 權杖結構
Kubernetes ServiceAccount 權杖看起來如下:
{
"aud": ["litellm-proxy"],
"exp": 1234567890,
"iat": 1234567890,
"iss": "https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLE",
"kubernetes.io": {
"namespace": "my-app",
"pod": {
"name": "llm-client-pod",
"uid": "pod-uid"
},
"serviceaccount": {
"name": "my-llm-client",
"uid": "sa-uid"
}
},
"nbf": 1234567890,
"sub": "system:serviceaccount:my-app:my-llm-client"
}
進階:使用名稱解析將 Namespace 對應至 Team
使用 team_alias_jwt_field 可自動將 namespaces 解析為 teams:
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
user_id_jwt_field: "sub"
# Map the namespace to team_alias in the database
team_alias_jwt_field: 'kubernetes\.io.namespace'
user_id_upsert: true
如此一來,namespace production 中的 pods 會自動與具有 team_alias: production 的 team 建立關聯。
設定可接受的 JWT scope 名稱
變更 JWT 'scopes' 中的字串,讓 litellm 評估使用者是否具有管理員存取權。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
admin_jwt_scope: "litellm-proxy-admin"
追蹤終端使用者 / 內部使用者 / Team / Org
設定 jwt 權杖中的欄位,該欄位對應到 litellm 使用者 / team / org。
**注意:**所有 JWT 欄位都支援點號表示法以存取巢狀 claims(例如,"user.sub"、"resource_access.client.roles")。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
admin_jwt_scope: "litellm-proxy-admin"
team_id_jwt_field: "client_id" # 👈 CAN BE ANY FIELD (supports dot notation for nested claims)
user_id_jwt_field: "sub" # 👈 CAN BE ANY FIELD (supports dot notation for nested claims)
org_id_jwt_field: "org_id" # 👈 CAN BE ANY FIELD (supports dot notation for nested claims)
end_user_id_jwt_field: "customer_id" # 👈 CAN BE ANY FIELD (supports dot notation for nested claims)
預期的 JWT(扁平結構):
{
"client_id": "my-unique-team",
"sub": "my-unique-user",
"org_id": "my-unique-org"
}
或使用點號表示法的巢狀結構:
{
"user": {
"sub": "my-unique-user",
"email": "user@example.com"
},
"tenant": {
"team_id": "my-unique-team"
},
"organization": {
"id": "my-unique-org"
}
}
巢狀範例的設定:
litellm_jwtauth:
user_id_jwt_field: "user.sub"
user_email_jwt_field: "user.email"
team_id_jwt_field: "tenant.team_id"
org_id_jwt_field: "organization.id"
現在 litellm 會在每次呼叫時,自動更新資料庫中該使用者/team/org 的支出。
以名稱(別名)而非 ID 解析
有時您的 JWT 權杖會包含人類可讀的名稱,而不是資料庫 ID。LiteLLM 可以透過在資料庫中查找,將這些名稱解析為 ID。
**使用情境:**您的 IDP 在 JWT 中提供 team/org 名稱,但 LiteLLM 進行支出追蹤與存取控制時,需要實際的資料庫 ID。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
# Name-based fields (resolved via database lookup)
team_alias_jwt_field: "team_alias" # Resolves team by team_alias in DB
org_alias_jwt_field: "org_alias" # Resolves org by organization_alias in DB
預期的 JWT:
{
"sub": "user-123",
"team_alias": "engineering-team",
"org_alias": "acme-corp"
}
運作方式:
- LiteLLM 從已設定的 JWT 欄位擷取名稱
- 依據別名欄位在資料庫中查找該實體:
- Teams:
team_alias欄位於LiteLLM_TeamTable - Organizations:
organization_alias欄位於LiteLLM_OrganizationTable
- Teams:
- 使用解析後的 ID 進行支出追蹤與存取控制
**優先順序:**ID 欄位一律優先於名稱欄位。如果 team_id_jwt_field 與 team_alias_jwt_field 都已設定,且兩者的值都存在於 JWT 中,則會使用 ID。
# Example: ID takes precedence
litellm_jwtauth:
team_id_jwt_field: "team_id" # Used if present in JWT
team_alias_jwt_field: "team_alias" # Fallback if team_id not present
**巢狀欄位:**名稱欄位也支援點號表示法以處理巢狀 claims:
litellm_jwtauth:
team_alias_jwt_field: "organization.team.name"
org_alias_jwt_field: "company.name"
重要注意事項:
- 該實體(team/org)必須已存在於資料庫中,且具有相符的別名
- 別名應保持唯一 - 如果多個實體共享相同別名,將回傳錯誤
- 名稱解析需要額外的資料庫查找,因此直接使用 ID 的效能會略佳
JWT 範圍
以下是 JWT 驗證權杖上的 scopes 樣式
可以是清單
scope: ["litellm-proxy-admin",...]
可以是以空白分隔的字串
scope: "litellm-proxy-admin ..."
使用 Teams 控制模型存取
- 指定包含使用者所屬 team ids 的 JWT 欄位。
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
user_id_jwt_field: "sub"
team_ids_jwt_field: "groups"
user_id_upsert: true # add user_id to the db if they don't exist
enforce_team_based_model_access: true # don't allow users to access models unless the team has access
這是假設您的權杖看起來如下:
{
...,
"sub": "my-unique-user",
"groups": ["team_id_1", "team_id_2"]
}
- 在 LiteLLM 上建立 teams
curl -X POST '<PROXY_BASE_URL>/team/new' \
-H 'Authorization: Bearer <PROXY_MASTER_KEY>' \
-H 'Content-Type: application/json' \
-D '{
"team_alias": "team_1",
"team_id": "team_id_1" # 👈 MUST BE THE SAME AS THE SSO GROUP ID
}'
- 測試流程
UI 的 SSO:查看逐步說明
API 的 OIDC 驗證:查看逐步說明
流程
- 驗證使用者 id 是否存在於資料庫中(LiteLLM_UserTable)
- 驗證任一 group 是否存在於資料庫中(LiteLLM_TeamTable)
- 驗證任一 group 是否擁有模型存取權
- 若所有檢查都通過,則允許該請求
透過請求標頭選擇 Team
當 JWT 權杖包含多個 teams(透過 team_ids_jwt_field)時,您可以透過傳遞 x-litellm-team-id 標頭,明確選擇要用於某個請求的 team。
此標頭可接受團隊的 team_id 或其 team_alias。LiteLLM 會先將該值與 JWT 授予的團隊 id 比對;若不屬於其中之一,LiteLLM 會以該別名查找團隊,且只有在該團隊的 id 也是 JWT 授予的其中之一時才接受。無論哪種情況,請求都會以 canonical 的 team_id 執行,因此預算、模型存取、速率限制、支出記錄,以及資料庫中的 team_id 欄位都會顯示 id,而不會顯示別名。傳送 id 可略過別名查找。
curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-jwt-token>' \
-H 'x-litellm-team-id: team_id_2' \
-d '{
"model": "gpt-5.6-terra",
"messages": [{"role": "user", "content": "Hello"}]
}'
同一個請求若改用 team_id_2 的別名(設定於 /team/new 的 team_alias)也會解析為同一個團隊:
curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-jwt-token>' \
-H 'x-litellm-team-id: team_2' \
-d '{
"model": "gpt-5.6-terra",
"messages": [{"role": "user", "content": "Hello"}]
}'
驗證:
- 該值必須是 JWT 的
team_ids_jwt_field清單中的團隊 id(或team_id_jwt_field值),或其中某個團隊的別名 - 若該值既不是團隊 id 也不是別名,包括 JWT 未授予之團隊的別名,會回傳 403,訊息會說明該值未匹配任何 team id 或 team alias,並列出 JWT 允許的 team id
- 多個團隊共用的別名永遠不會被解析;若要透過別名選擇團隊,請保持別名唯一
- 如果未提供標頭,LiteLLM 會自動選取第一個可存取所請求模型的團隊
使用 fallback_to_db_teams: true 且 JWT 不包含 team claim 時,標頭會改為依據資料庫中使用者的團隊成員資格來檢查,而不是依據 JWT,且別名同樣可接受:該值必須是使用者所屬團隊的 id 或別名,否則請求會以 403 被拒絕。
當 JWT claims 無法解析時,回退至資料庫中的 team
預設情況下,當已設定 team_id_jwt_field 或 team_ids_jwt_field,且 JWT 帶有一個不會對應到任何 LiteLLM 團隊的 claim 值時,LiteLLM 會拋出錯誤:此 claim 會被視為具有權威性。
對於 IdP 團隊 claim 為建議性的部署(例如 groups claim 位於與 LiteLLM team_ids 不同命名空間中的機器 token),可選擇啟用備援:如果已設定的 claim 存在但無法解析,LiteLLM 會改以使用者的單一 LiteLLM 團隊為準(當使用者在資料庫中恰好屬於一個團隊時)。
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
user_id_jwt_field: "sub"
team_ids_jwt_field: "groups"
team_claim_fallback: true # 👈 opt in
行為:
| 觸發條件 | 預設(team_claim_fallback: false) | 可選啟用(team_claim_fallback: true) |
|---|---|---|
team_id claim 解析為真實團隊 | 200 / 使用團隊 | 200 / 使用團隊 |
team_id claim 存在,但資料庫中找不到團隊 | raise | defer → 備援至使用者的單一資料庫團隊 |
team_alias claim 解析 | 200 / 使用團隊 | 200 / 使用團隊 |
groups claim 解析且團隊授權模型 | 200 | 200 |
groups claim 解析但團隊缺少模型 | 403(保留) | 403(保留) |
groups claim 存在,但沒有任何一個能解析為真實團隊 | 403 | defer → 備援至使用者的單一資料庫團隊 |
| 完全沒有 claim(單一團隊備援基準) | 200 / 備援 | 200 / 備援 |
安全範圍: 只有在使用者在資料庫中恰好屬於一個 LiteLLM 團隊時,才會觸發備援;非 404 錯誤(例如 "No DB Connected")一律會向外傳遞。如果您的 IdP 團隊 claims 是授權的權威來源,請維持預設(false)。
自訂 JWT 驗證
如果您需要額外方式驗證 token 是否對 LiteLLM Proxy 有效,可使用自訂邏輯驗證 JWT Token。
1. 設定自訂驗證函式
from typing import Literal
def my_custom_validate(token: str) -> Literal[True]:
"""
Only allow tokens with tenant-id == "my-unique-tenant", and claims == ["proxy-admin"]
"""
allowed_tenants = ["my-unique-tenant"]
allowed_claims = ["proxy-admin"]
if token["tenant_id"] not in allowed_tenants:
raise Exception("Invalid JWT token")
if token["claims"] not in allowed_claims:
raise Exception("Invalid JWT token")
return True
2. 設定 config.yaml
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
user_id_jwt_field: "sub"
team_id_jwt_field: "tenant_id"
user_id_upsert: True
custom_validate: custom_validate.my_custom_validate # 👈 custom validate function
3. 測試流程
預期 JWT
{
"sub": "my-unique-user",
"tenant_id": "INVALID_TENANT",
"claims": ["proxy-admin"]
}
預期回應
{
"error": "Invalid JWT token"
}
允許的路由
透過設定檔設定 JWT 可存取的路由。
預設情況下:
- 管理員:只能存取管理路由(
/team/*、/key/*、/user/*) - 團隊:只能存取 openai 路由(
/chat/completions等)+ 資訊路由(/*/info)
管理員路由
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
admin_jwt_scope: "litellm-proxy-admin"
admin_allowed_routes: ["/v1/embeddings"]
團隊路由
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
# ...
team_id_jwt_field: "litellm-team" # 👈 Set field in the JWT token that stores the team ID
team_allowed_routes: ["/v1/chat/completions"] # 👈 Set accepted routes
讓團隊可使用其他提供者路由
團隊 JWT 已可預設呼叫 /v1/messages 和 /v1/messages/count_tokens。若要讓團隊 JWT token 存取 anthropic_routes 中其他 Anthropic 風格的端點,請更新您 litellm_jwtauth 組態中的 team_allowed_routes。team_allowed_routes 支援以下值:
- 來自
LiteLLMRoutes的具名路由群組(例如openai_routes、anthropic_routes、info_routes、mapped_pass_through_routes)。 - 精確路由,例如
/v1/messages。 - 以
*結尾的路由前綴,例如/internal-models/*,可比對該前綴下的每一條路由。
以下是您可使用的路由群組快速參考,以及各群組的代表性範例路由。如果需要完整清單,請參閱 LiteLLMRoutes 中的 litellm/proxy/_types.py enum 作為權威清單。
| 路由群組 | 內容 | 代表性路由 |
|---|---|---|
openai_routes | OpenAI 相容的 REST 端點(chat、completion、embeddings、images、responses、models 等) | /v1/chat/completions、/v1/completions、/v1/embeddings、/v1/images/generations、/v1/models |
anthropic_routes | Anthropic 風格端點(/v1/messages 與相關端點) | /v1/messages、/v1/messages/count_tokens、/v1/skills |
mapped_pass_through_routes | 提供者專屬的轉發路由前綴(例如透過 /anthropic 轉發時的 Anthropic)。搭配 mapped_pass_through_routes 使用,以進行提供者萬用字元對應 | /anthropic/*、/vertex-ai/*、/bedrock/* |
passthrough_routes_wildcard | 提供者的萬用字元對應(例如 /anthropic/*)- 供 proxy 使用的預先計算萬用字元清單 | /anthropic/*、/vllm/* |
google_routes | Google 專屬(例如 Vertex / Batching 端點) | /v1beta/models/{model_name}:generateContent |
mcp_routes | 內部 MCP 管理端點 | /mcp/tools、/mcp/tools/call |
info_routes | UI 使用的唯讀與資訊端點 | /key/info、/team/info、/v1/models |
management_routes | 僅限管理員的管理端點(建立/更新/刪除 user/team/model) | /team/new、/key/generate、/model/new |
spend_tracking_routes | 預算/支出相關端點 | /spend/logs、/spend/keys、/spend/users |
public_routes | 公開與未驗證端點 | /、/routes、/.well-known/litellm-ui-config |
注意:llm_api_routes 是 OpenAI、Anthropic、Google、轉發與其他 LLM 路由(openai_routes + anthropic_routes + google_routes + mapped_pass_through_routes + passthrough_routes_wildcard + apply_guardrail_routes + mcp_routes + litellm_native_routes)的聯集。
預設值(若您未在 litellm_jwtauth 中覆寫,proxy 會使用的值):
admin_jwt_scope:litellm_proxy_adminadmin_allowed_routes(預設):management_routes、spend_tracking_routes、global_spend_tracking_routes、info_routesteam_allowed_routes(預設):openai_routes、info_routes、mcp_routes、/v1/messages、/v1/messages/count_tokens。設定team_allowed_routes會取代此清單,因此如果團隊仍需要mcp_routes和/v1/messages路由,請將它們加回來public_allowed_routes(預設):public_routes
範例:允許團隊 JWT 呼叫 Anthropic /v1/messages(可透過路由群組或明確路由字串):
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
team_ids_jwt_field: "team_ids"
team_allowed_routes: ["openai_routes", "info_routes", "anthropic_routes"]
或者只選擇性允許精確的 Anthropic message 端點:
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
team_ids_jwt_field: "team_ids"
team_allowed_routes: ["/v1/messages", "info_routes"]
如果您註冊了共用同一前綴的 passthrough 端點,請一次以尾端 * 授權該前綴,這樣之後新增的路由就能涵蓋到,而不需要再修改設定。admin_allowed_routes 支援相同的模式。
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
team_ids_jwt_field: "team_ids"
team_allowed_routes: ["openai_routes", "info_routes", "/internal-models/*"]
只有尾端 * 會被視為萬用字元,且它會比對前綴下方的路由,因此 /internal-models/* 會涵蓋 /internal-models/anthropic/v1/messages,但不包含裸的 /internal-models 路由。
快取 Public Keys
控制 public keys 的快取時間長度(以秒為單位)。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
admin_jwt_scope: "litellm-proxy-admin"
admin_allowed_routes: ["/v1/embeddings"]
public_key_ttl: 600 # 👈 KEY CHANGE
自訂 JWT 欄位
設定 team_id 所在的自訂欄位。預設會檢查 'client_id' 欄位。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
team_id_jwt_field: "client_id" # 👈 KEY CHANGE
封鎖團隊
若要封鎖某個 team id 的所有請求,請使用 /team/block
封鎖團隊
curl --location 'http://0.0.0.0:4000/team/block' \
--header 'Authorization: Bearer <admin-token>' \
--header 'Content-Type: application/json' \
--data '{
"team_id": "litellm-test-client-id-new" # 👈 set team id
}'
解除封鎖團隊
curl --location 'http://0.0.0.0:4000/team/unblock' \
--header 'Authorization: Bearer <admin-token>' \
--header 'Content-Type: application/json' \
--data '{
"team_id": "litellm-test-client-id-new" # 👈 set team id
}'
Upsert 使用者 + 允許的電子郵件網域
允許屬於特定電子郵件網域的使用者自動存取 proxy。
注意: user_allowed_email_domain 為選填。若未指定,所有使用者都將被允許,不論其電子郵件網域為何。
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
enable_jwt_auth: True
litellm_jwtauth:
user_email_jwt_field: "email" # 👈 checks 'email' field in jwt payload
user_allowed_email_domain: "my-co.com" # 👈 OPTIONAL - allows user@my-co.com to call proxy
user_id_upsert: true # 👈 upserts the user to db, if valid email but not in db
OIDC UserInfo 端點
當您的 JWT/access token 不包含可識別使用者的資訊時,請使用此功能。LiteLLM 會呼叫您的身分提供者的 UserInfo 端點以擷取使用者詳細資料。
何時使用
- 您的 JWT 是不透明的(非自包含)或缺少使用者 claims
- 您需要從身分提供者取得最新的使用者資訊
- 您的 access tokens 不包含 email、roles 或其他識別資料
設定
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
# Enable OIDC UserInfo endpoint
oidc_userinfo_enabled: true
oidc_userinfo_endpoint: "https://your-idp.com/oauth2/userinfo"
oidc_userinfo_cache_ttl: 300 # Cache for 5 minutes (default: 300)
# Map fields from UserInfo response
user_id_jwt_field: "sub"
user_email_jwt_field: "email"
user_roles_jwt_field: "roles"
流程圖
範例:Azure AD
litellm_jwtauth:
oidc_userinfo_enabled: true
oidc_userinfo_endpoint: "https://graph.microsoft.com/oidc/userinfo"
user_id_jwt_field: "sub"
user_email_jwt_field: "email"
範例:Keycloak
litellm_jwtauth:
oidc_userinfo_enabled: true
oidc_userinfo_endpoint: "https://keycloak.example.com/realms/your-realm/protocol/openid-connect/userinfo"
user_id_jwt_field: "sub"
user_roles_jwt_field: "resource_access.your-client.roles"
將 JWT 形狀的機器 tokens 路由至 OAuth2
在以下情況使用:
enable_jwt_auth: true進行標準 JWT 驗證- 機器 tokens 為 JWT 形狀,且應根據 claims 路由至 OAuth2
routing_overrides 支援兩種運作模式:
- 選擇性模式:設定
enable_oauth2_auth: false,只將符合條件的 JWT 傳送至 LLM + 資訊路由上的 OAuth2 - 全域模式:設定
enable_oauth2_auth: true,也在 LLM + 資訊路由上啟用 OAuth2
general_settings:
enable_jwt_auth: true
enable_oauth2_auth: false
litellm_jwtauth:
user_id_jwt_field: "sub"
routing_overrides:
- iss: "machine-issuer.example.com"
client_id: "MID_LITELLM"
path: "oauth2"
比對行為
- 當所有已設定的選擇器都與對應的 token claim 相符時,規則即成立(AND 語意)。
- 支援的選擇器:
iss(必填)、client_id(選填)、scope(選填)、aud(選填)。 - 選擇器值可以是單一字串或字串清單(claim 至少必須符合其中一項,並依下列規則比對)。
- 萬用字元: 選擇器可使用 shell 風格的
*與?。比對是區分大小寫的,因此請使用與您的 IdP 在 JWT claim 中輸出的相同大小寫。 scopeclaim 作為以空格分隔的字串: OAuth/OIDC 常會將scope以單一字串傳送(例如openid profile App:LiteLLM)。LiteLLM 只有在比對scope選擇器時才會將該字串拆分,因此像App:LiteLLM這樣的設定值可以比對成功。iss、aud和client_id絕不會以空格拆分;會使用完整的 claim 字串(路由只使用未驗證的 claim 進行路徑選擇;最終驗證仍會驗證 token)。- 如果沒有任何規則匹配,LiteLLM 會繼續進行標準 JWT 驗證。
範例:scope 與萬用字元 client_id
general_settings:
enable_jwt_auth: true
enable_oauth2_auth: false
litellm_jwtauth:
routing_overrides:
- iss: "machine-issuer.example.com"
scope: "App:LiteLLM"
client_id: "*MID_LITELLM"
path: "oauth2"
清單式覆寫範例
general_settings:
enable_jwt_auth: true
enable_oauth2_auth: false
litellm_jwtauth:
routing_overrides:
- iss: ["machine-issuer.example.com", "backup-issuer.example.com"]
client_id: ["MID_LITELLM", "MID_BACKUP"]
aud: ["api://litellm", "api://fallback"]
path: "oauth2"
[BETA] 使用 OIDC 角色控管存取
允許具備支援角色的 JWT token 存取 proxy。
讓使用者與團隊可以存取 proxy,而不需要將他們加入資料庫。
非常重要,請設定 enforce_rbac: true 以確保 RBAC 系統已啟用。
注意: 這項功能目前為 beta,可能會在未經通知的情況下變更。
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
object_id_jwt_field: "oid" # can be either user / team, inferred from the role mapping
roles_jwt_field: "roles"
role_mappings:
- role: litellm.api.consumer
internal_role: "team"
enforce_rbac: true # 👈 VERY IMPORTANT
role_permissions: # default model + endpoint permissions for a role.
- role: team
models: ["anthropic-claude"]
routes: ["/v1/chat/completions"]
environment_variables:
JWT_AUDIENCE: "api://LiteLLM_Proxy" # ensures audience is validated
-
object_id_jwt_field:JWT token 中包含 object id 的欄位。此 id 可以是 user id 或 team id。請使用此欄位取代user_id_jwt_field和team_id_jwt_field。若同一欄位可能同時是兩者。支援點記法 以處理巢狀聲明(例如,"profile.object_id")。 -
roles_jwt_field:JWT token 中包含 roles 的欄位。此欄位是一個使用者所擁有角色的清單。支援點記法 用於巢狀欄位 - 例如,resource_access.litellm-test-client-id.roles。
其他 JWT 欄位設定選項:
-
team_ids_jwt_field:包含團隊 ID 的欄位(以清單形式)。支援點記法(例如"groups"、"teams.ids")。 -
user_email_jwt_field:包含使用者電子郵件的欄位。支援點記法(例如"email"、"user.email")。 -
end_user_id_jwt_field:包含用於成本追蹤的終端使用者 ID 的欄位。支援點記法(例如"customer_id"、"customer.id")。當設定此項時,來自已驗證 JWT claim 的終端使用者 ID 會優先於任何請求提供的值(例如標頭x-litellm-end-user-id或本文欄位metadata.user_id;請參閱[customer ID 優先順序](customers#1-make-llm-api-call-w-customer-id))。 -
role_mappings:角色對應清單。將 JWT token 中收到的角色對應到 LiteLLM 的內部角色。 -
JWT_AUDIENCE:JWT token 的 audience。這用於驗證 JWT token 的 audience。透過環境變數設定。
Token 範例
{
"aud": "api://LiteLLM_Proxy",
"oid": "eec236bd-0135-4b28-9354-8fc4032d543e",
"roles": ["litellm.api.consumer"]
}
角色對應規格
role:JWT token 中預期的角色。internal_role:LiteLLM 上將用於控制存取的內部角色。
支援的內部角色:
team:將使用 Team 物件進行 RBAC 花費追蹤。請用於追蹤某個「使用情境」的花費。internal_user:將使用 User 物件進行 RBAC 花費追蹤。請用於追蹤某個「個別使用者」的花費。proxy_admin:將使用 Proxy admin 進行 RBAC 花費追蹤。請用於授予 token 管理員存取權限。
架構圖(控制模型存取)
[BETA] 使用 Scopes 控制模型存取
控制 JWT 可以存取哪些模型。設定 enforce_scope_based_access: true 以強制執行以 scope 為基礎的存取控制。
1. 使用 scope 對應設定 config.yaml。
model_list:
- model_name: anthropic-claude
litellm_params:
model: anthropic/claude-sonnet-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: gpt-3.5-turbo-testing
litellm_params:
model: gpt-5.6-luna
api_key: os.environ/OPENAI_API_KEY
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
team_id_jwt_field: "client_id" # 👈 set the field in the JWT token that contains the team id
team_id_upsert: true # 👈 upsert the team to db, if team id is not found in db
scope_mappings:
- scope: litellm.api.consumer
models: ["anthropic-claude"]
- scope: litellm.api.gpt_3_5_turbo
models: ["gpt-3.5-turbo-testing"]
enforce_scope_based_access: true # 👈 enforce scope-based access control
enforce_rbac: true # 👈 enforces only a Team/User/ProxyAdmin can access the proxy.
Scope 對應規格
scope:JWT token 要使用的 scope。models:JWT token 可以存取的模型。值為model_name中的model_list。注意:目前不支援萬用字元路由。
2. 建立具有正確 scopes 的 JWT。
預期的 Token:
{
"scope": ["litellm.api.consumer", "litellm.api.gpt_3_5_turbo"] # can be a list or a space-separated string
}
3. 測試流程。
curl -L -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer eyJhbGci...' \
-d '{
"model": "gpt-3.5-turbo-testing",
"messages": [
{
"role": "user",
"content": "Hey, how'\''s it going 1234?"
}
]
}'
[BETA] 與 IDP 同步使用者角色與團隊
將您的 Identity Provider(IDP)中的使用者角色與團隊成員資格自動同步到 LiteLLM 的資料庫。這可確保 LiteLLM 中的使用者權限與團隊成員資格與您的 IDP 保持同步。
注意: 這項功能目前為 beta,可能會在未經通知的情況下變更。
使用情境
- 角色同步:當使用者在您的 IDP 中變更角色時,自動更新 LiteLLM 中的使用者角色
- 團隊成員資格同步:讓您的 IDP 與 LiteLLM 之間的團隊成員資格保持同步
- 集中式存取管理:透過您的 IDP 管理所有使用者權限,同時維持 LiteLLM 功能
設定
1. 設定 JWT 角色對應
將 JWT token 中的角色對應到 LiteLLM 使用者角色:
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
user_id_jwt_field: "sub"
team_ids_jwt_field: "groups"
roles_jwt_field: "roles"
user_id_upsert: true
sync_user_role_and_teams: true # 👈 Enable sync functionality
jwt_litellm_role_map: # 👈 Map JWT roles to LiteLLM roles
- jwt_role: "ADMIN"
litellm_role: "proxy_admin"
- jwt_role: "USER"
litellm_role: "internal_user"
- jwt_role: "VIEWER"
litellm_role: "internal_user"
2. JWT 角色對應規格
jwt_role:JWT token 中顯示的角色名稱。支援使用fnmatch的萬用字元樣式(例如,"ADMIN_*"可匹配"ADMIN_READ"、"ADMIN_WRITE"等)litellm_role:對應的 LiteLLM 使用者角色
支援的 LiteLLM 角色:
proxy_admin:完整管理存取權internal_user:標準使用者存取權internal_user_view_only:唯讀存取權
3. JWT Token 範例
{
"sub": "user-123",
"roles": ["ADMIN"],
"groups": ["team-alpha", "team-beta"],
"iat": 1234567890,
"exp": 1234567890
}
運作方式
當使用者帶著 JWT token 發出請求時:
-
角色同步:
- LiteLLM 會檢查 JWT 中使用者的角色是否與資料庫中的角色一致
- 如果不同,使用者角色會在 LiteLLM 的資料庫中更新
- 使用
jwt_litellm_role_map將 JWT 角色轉換為 LiteLLM 角色
-
團隊成員資格同步:
- 比對 JWT token 中的團隊成員資格與 LiteLLM 中該使用者目前的團隊
- 將使用者加入 JWT 中出現的新團隊
- 將使用者從 JWT 中未出現的團隊移除
-
資料庫更新:
- 更新會在驗證程序期間自動進行
- 不需要手動介入
設定選項
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
# Required fields
user_id_jwt_field: "sub"
team_ids_jwt_field: "groups"
roles_jwt_field: "roles"
# Sync configuration
sync_user_role_and_teams: true
user_id_upsert: true
# Role mapping
jwt_litellm_role_map:
- jwt_role: "AI_ADMIN_*" # Wildcard pattern
litellm_role: "proxy_admin"
- jwt_role: "AI_USER"
litellm_role: "internal_user"
重要注意事項
- 效能:同步操作會在驗證期間進行,可能會增加些微延遲
- 資料庫存取:需要資料庫存取權才能更新使用者與團隊
- 團隊建立:JWT token 中提到的團隊必須先存在於 LiteLLM 中,之後同步才能將使用者指派給它們
- 萬用字元支援:JWT 角色樣式支援使用
fnmatch的萬用字元比對
測試同步功能
- 建立一個初始角色的測試使用者:
curl -X POST 'http://0.0.0.0:4000/user/new' \
-H 'Authorization: Bearer <PROXY_MASTER_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"user_id": "user-123",
"user_role": "internal_user"
}'
- 發出一個包含不同角色的 JWT 請求:
curl -X POST 'http://0.0.0.0:4000/v1/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <JWT_WITH_ADMIN_ROLE>' \
-d '{
"model": "claude-sonnet-5",
"messages": [{"role": "user", "content": "Hello"}]
}'
- 驗證角色已更新:
curl -X GET 'http://0.0.0.0:4000/user/info?user_id=user-123' \
-H 'Authorization: Bearer <PROXY_MASTER_KEY>'
[BETA] JWT 到虛擬金鑰對應
將 JWT 身分對應到 LiteLLM 虛擬金鑰,讓使用 JWT 驗證的使用者獲得按使用者區分的預算、速率限制、模型存取控制與花費追蹤。
當 JWT 傳入時,LiteLLM 會在對應表中查找已設定的 claim(例如 email、sub)。如果存在對應,則該請求會被視為是透過相應的虛擬金鑰送達,且所有虛擬金鑰功能都會套用。
設定
將 virtual_key_claim_field 加入您的 JWT 驗證設定:
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
virtual_key_claim_field: "email" # JWT claim to look up (supports dot notation)
virtual_key_mapping_cache_ttl: 300 # Cache TTL in seconds (default: 300)
管理對應
所有端點都需要管理員驗證(Authorization: Bearer <master_key>)。
建立對應。 將 JWT claim 值連結到現有的虛擬金鑰:
curl -X POST http://localhost:4000/jwt/key/mapping/new \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jwt_claim_name": "email",
"jwt_claim_value": "user@example.com",
"key": "sk-virtual-key-from-key-generate"
}'
列出對應(分頁):
curl http://localhost:4000/jwt/key/mapping/list?page=1&size=50 \
-H "Authorization: Bearer $LITELLM_API_KEY"
取得特定對應:
curl "http://localhost:4000/jwt/key/mapping/info?id=<mapping-id>" \
-H "Authorization: Bearer $LITELLM_API_KEY"
更新對應:
curl -X POST http://localhost:4000/jwt/key/mapping/update \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "<mapping-id>",
"description": "Updated description",
"is_active": true
}'
刪除對應:
curl -X POST http://localhost:4000/jwt/key/mapping/delete \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"id": "<mapping-id>"}'
運作方式
- 請求攜帶 JWT bearer token 抵達
- LiteLLM 驗證 JWT 簽章
- 擷取已設定的 claim(例如
email→user@example.com) - 在
LiteLLM_JWTKeyMapping表中查找 claim 值 - 如果存在對應,則請求會如同使用已對應的虛擬金鑰般繼續處理,因此預算、速率限制、模型存取與支出追蹤都會套用
- 如果沒有對應,則回退到標準 JWT 驗證(團隊層級控制)
錯誤代碼
| 代碼 | 含義 |
|---|---|
| 409 | 重複對應 — 該 claim 名稱 + 值的對應已存在 |
| 400 | 提供的金鑰與現有虛擬金鑰不符 |
| 404 | 找不到對應(用於更新/刪除/資訊) |
| 403 | 非管理員使用者嘗試執行對應操作 |
將 JWT 綁定到已註冊的代理程式
在您的身分識別提供者中佈建代理程式身分(例如,每個代理程式對應一個 Microsoft Entra ID app registration),並讓 LiteLLM 對該代理程式所呈現的每個 JWT 強制執行其政策。當設定 agent_id_jwt_field 時,LiteLLM 會從已驗證的 token 讀取該 claim,將其與已註冊的代理程式比對(先依 agent_id,再依 agent_name),並將 agent_id 設定在已驗證身分上。原本已適用於綁定代理程式的虛擬金鑰的一切,也會同樣適用於 JWT 呼叫端:require_trace_id_on_calls_by_agent、每個代理程式的 MCP server 與工具限制,以及 agent_id 支出歸屬。
設定
請以您的身分識別提供者會傳送的名稱註冊該代理程式。對於 Entra app token 而言,那就是 client id,Entra 會將其放在 azp claim(v2 tokens)或 appid(v1 tokens)中。
agents:
- agent_name: 2f5c9b1e-6a4d-4c8e-9f0b-7d1a3e5c9b21 # Entra client id of the agent's app registration
agent_card_params:
name: research-agent
url: http://localhost:9999/a2a
version: "1.0.0"
litellm_params:
require_trace_id_on_calls_by_agent: true
general_settings:
enable_jwt_auth: True
litellm_jwtauth:
agent_id_jwt_field: "azp" # supports dot notation for nested claims
team_id_jwt_field: "team"
user_id_jwt_field: "sub"
行為
其 claim 與已註冊代理程式相符的 token,會綁定到該代理程式並繼承其限制,因此在上述設定下,沒有 x-litellm-trace-id 的呼叫會以 400 被拒絕。其 claim 與任何已註冊代理程式都不相符的 token,會以 403 被拒絕,而不會回退為未綁定的身分,這與未知的 team_id_jwt_field 值被拒絕的方式相同;這也適用於 admin 範圍的 token。完全不帶該 claim 的 token,則會如同以往一樣完成驗證。當 agent_id_jwt_field 未設定時,不會有任何變更。
任何帶有已設定 claim 的 token 都會被視為代理程式。Entra 也會將 azp 放在 delegated(user)tokens 上,因此如果人類與代理程式為同一個 audience 取得 token,azp 也會綁定或拒絕人類呼叫者。在那種設定下,請將 agent_id_jwt_field 指向只有代理程式 token 才會帶有的 claim,例如 optional claim,或透過代理程式 app registrations 上的 claims mapping policy 新增的自訂 claim,並讓 azp 保留給所有 JWT 呼叫端皆為代理程式的 proxy。
如果該 token 也透過[JWT-to-Virtual-Key Mapping](#beta-jwt-to-virtual-key-mapping) 對應到虛擬金鑰,則會使用對應金鑰自身的 agent_id,且該請求不會查詢 agent_id_jwt_field。