Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
61a1122
feat(anthropic): workload identity federation via a shared RFC 7523 t…
derhornspieler Aug 22, 2026
20da15e
fix(anthropic): stop workload identity federation from reaching non-A…
derhornspieler Aug 23, 2026
79e4a69
fix(anthropic): keep workload identity federation out of caller-contr…
derhornspieler Aug 23, 2026
66a3744
feat(anthropic): pluggable identity sources for workload identity fed…
derhornspieler Aug 23, 2026
cb3f29d
feat(proxy): provider-level setup for Anthropic workload identity fed…
derhornspieler Aug 23, 2026
d626d65
fix(proxy): let the model table validate a row it was handed as an ob…
derhornspieler Aug 23, 2026
ff457a7
chore(ui): add the new provider-setup endpoints to the dashboard API …
derhornspieler Aug 23, 2026
fb4065d
style(ui): apply prettier to the new provider-setup modules
derhornspieler Aug 23, 2026
2ee90c2
fix(anthropic): redact the assertion that was actually sent, and form…
derhornspieler Aug 23, 2026
3562661
fix(anthropic): mint the files and batches credential without blockin…
derhornspieler Aug 23, 2026
b0a28b2
fix(proxy): let only proxy admins persist Anthropic workload identity…
derhornspieler Aug 23, 2026
cc18f80
fix(ui): keep the add-provider tab after auto-routers, and drop alias…
derhornspieler Aug 23, 2026
498592e
test(anthropic): cover the token exchange and Keycloak default posters
derhornspieler Aug 23, 2026
3c5b467
chore(ui): regenerate the dashboard API types for the split credentia…
derhornspieler Aug 23, 2026
db268de
fix(anthropic): scale the token refresh windows to the token's own li…
derhornspieler Aug 23, 2026
6c89af0
fix(proxy): gate every credential write path on the effective workloa…
derhornspieler Aug 23, 2026
c9063a2
fix(anthropic): stop caller keys riding upstream beside a server-mint…
derhornspieler Aug 23, 2026
d3ee6c6
ci: give the unit job the setup headroom its own startup guard requires
derhornspieler Aug 23, 2026
67688e1
feat(anthropic): report workload identity token health as a litellm s…
derhornspieler Aug 23, 2026
0a88371
fix(anthropic): bound the token metrics backlog so a stalled backend …
derhornspieler Aug 23, 2026
0a69790
refactor(anthropic): drop the recursion the workload identity paths d…
derhornspieler Aug 23, 2026
79b5738
fix(proxy): read both memory and the row when authorizing a credentia…
derhornspieler Aug 23, 2026
e71d5cf
fix(anthropic): keep the token cache at its bound after a burst of di…
derhornspieler Aug 23, 2026
8655283
fix(anthropic): stop annotating loop-assigned locals as Final
derhornspieler Aug 23, 2026
d832b80
fix(anthropic): pin the federated token exchange to trusted hosts
derhornspieler Aug 23, 2026
576ada8
fix(ui): let the internal-issuer flow save before a federation rule i…
derhornspieler Aug 23, 2026
bacf9c9
fix(ui): harden the Add Provider wizard against three failure modes
derhornspieler Aug 24, 2026
2b1e56b
fix(ui): hide the Add Provider wizard from view-only admins
derhornspieler Aug 24, 2026
2bdd5be
fix(anthropic): stop the files surface forwarding a caller credential…
derhornspieler Aug 24, 2026
b2fb6dd
fix(anthropic): make the workspace id server-owned, and close two mor…
derhornspieler Aug 24, 2026
dc35845
fix(anthropic): finish the caller-credential sweep and stop echoing a…
derhornspieler Aug 24, 2026
0a55190
fix(anthropic): evaluate the federation admin rule against the result…
derhornspieler Aug 24, 2026
33ed7b1
fix(anthropic): count tokens through the federated credential
derhornspieler Aug 24, 2026
0602670
Merge remote-tracking branch 'upstream/litellm_internal_staging' into…
derhornspieler Aug 24, 2026
6594e0a
fix(ui): point the provider wizard at the shadcn field primitive
derhornspieler Aug 25, 2026
d51d3eb
fix(auth): redact an echoed assertion however the endpoint returns it
derhornspieler Aug 25, 2026
e14811b
fix(auth): redact the encoded form of a client secret as well as the …
derhornspieler Aug 25, 2026
7076219
fix(auth): compare both sides of a reflected credential, and cover th…
derhornspieler Aug 25, 2026
c4a5459
fix(anthropic): carry the federation disable sentinel through the kwa…
derhornspieler Aug 25, 2026
197fd1e
fix: build the reflection candidates in one shot, and resync the gene…
derhornspieler Aug 25, 2026
f3b2a46
fix(auth): recognise a space written as "+" in a form-encoded credential
derhornspieler Aug 25, 2026
d3e3fda
fix(proxy): count the credential a deployment already carries, not on…
derhornspieler Aug 25, 2026
b5e757c
fix(ui): treat a cleared credential field as a deletion
derhornspieler Aug 25, 2026
eafb839
Merge remote-tracking branch 'upstream/litellm_internal_staging' into…
derhornspieler Aug 26, 2026
85763e7
fix(ci): clear the gate regressions the second merge introduced
derhornspieler Aug 26, 2026
743b918
chore: drop the dashboard build artifacts from this branch
derhornspieler Aug 26, 2026
0a923aa
fix(anthropic): stop model discovery crashing on the second page
derhornspieler Aug 26, 2026
c2b953e
fix(tests): pass anthropic federation params as keywords, not dict sp…
derhornspieler Aug 26, 2026
457a0c3
fix(router): type the params mapping spread into LiteLLM_Params
derhornspieler Aug 26, 2026
48a59a1
Merge remote-tracking branch 'origin/litellm_internal_staging' into l…
mateo-berri Aug 29, 2026
9f2b59c
fix(auth): compare a short secret whole when scanning for a reflected…
derhornspieler Aug 29, 2026
0455cb4
test(anthropic): expect the missing-credential error on MiniMax and T…
derhornspieler Aug 29, 2026
a7ed600
chore(terraform): allowlist the credential JWKS endpoint in the cover…
derhornspieler Aug 29, 2026
230b7f6
fix(anthropic): resolve the WIF identity source from a dense litellm_…
mateo-berri Aug 29, 2026
142092a
fix(anthropic): validate federated credentials off the event loop in …
mateo-berri Aug 29, 2026
f2240df
fix(proxy): keep WIF secret pointers unresolved when expanding os.env…
mateo-berri Aug 29, 2026
57b9e94
fix(ui): reset the add-provider form when the provider changes
mateo-berri Aug 29, 2026
f8b3184
fix(auth): import PyJWT and cryptography at use time so a base litell…
mateo-berri Aug 29, 2026
ff59884
fix(anthropic_wif): let deployment token refs beat the env identity s…
mateo-berri Aug 29, 2026
8402ae9
Merge remote-tracking branch 'origin/litellm_internal_staging' into l…
mateo-berri Aug 30, 2026
c4d2f03
test(savings): pin the local cost map on the no-cache-read baseline test
mateo-berri Aug 30, 2026
068c1d1
Merge remote-tracking branch 'origin/litellm_internal_staging' into l…
mateo-berri Aug 30, 2026
c6f585e
fix(anthropic): token counter honors ANTHROPIC_AUTH_TOKEN and degrade…
mateo-berri Aug 30, 2026
c813cc7
Merge remote-tracking branch 'origin/litellm_internal_staging' into l…
mateo-berri Sep 2, 2026
412890f
fix(anthropic): derive the count-tokens URL from the deployment api_base
mateo-berri Sep 2, 2026
272ccfd
fix(anthropic): resolve the count-tokens base like chat when the depl…
mateo-berri Sep 2, 2026
c0739de
Merge branch 'litellm_internal_staging' into litellm_internal_copy_38013
mateo-berri Sep 2, 2026
55e303e
test(auth): call the renamed has_user_setup_sso helper after the stag…
mateo-berri Sep 2, 2026
4a785c8
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 3, 2026
0a6f606
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 3, 2026
cb03462
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 3, 2026
3794ba9
fix(anthropic): resolve the count-tokens static key the way chat does
mateo-berri Sep 3, 2026
9036b90
Merge remote-tracking branch 'origin/litellm_internal_staging' into l…
mateo-berri Sep 3, 2026
bf71e09
feat(proxy): configure OpenAI workload identity federation from the A…
mateo-berri Sep 3, 2026
994c6f0
fix(openai): keep the get_models env fallback to a missing key only a…
mateo-berri Sep 3, 2026
fe6a535
fix(openai): let workload identity federation target the regional api…
mateo-berri Sep 3, 2026
6c7d3af
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 3, 2026
10d8449
Merge pull request #39613 from BerriAI/litellm_ui_openai_wif_add_model
mateo-berri Sep 3, 2026
055eaee
Merge remote-tracking branch 'origin/litellm_internal_staging' into l…
mateo-berri Sep 3, 2026
37f2de1
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 3, 2026
7a9ee45
fix(openai): treat an empty api_base as unset when discovering models
mateo-berri Sep 4, 2026
56cf0cd
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 4, 2026
1caa2fa
fix(proxy): keep an empty credential value empty after decryption
mateo-berri Sep 4, 2026
5e5c436
fix(ui): collect every Anthropic federation id on the Register issuer…
mateo-berri Sep 4, 2026
669f028
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 4, 2026
3a46fa2
refactor(ui): make LLM Credentials the one place to add provider cred…
mateo-berri Sep 4, 2026
4592e71
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 4, 2026
216da96
Merge branch 'litellm_internal_staging' of https://github.com/BerriAI…
mateo-berri Sep 5, 2026
82afbbd
fix(anthropic_wif): treat blank identity-source fields as unset
mateo-berri Sep 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/routes/allowlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"/credentials",
"/credential",
"/provider/budgets",
"/provider/models/discover",
# Tools / agents (registry & policy admin)
"/v1/tool/",
"/v1/agents",
Expand Down
8 changes: 7 additions & 1 deletion litellm/batches/batch_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

import litellm
from litellm._logging import verbose_logger
from litellm.litellm_core_utils.get_litellm_params import AWS_CREDENTIAL_KWARGS_KEYS
from litellm.litellm_core_utils.get_litellm_params import (
ANTHROPIC_WIF_KWARGS_KEYS,
AWS_CREDENTIAL_KWARGS_KEYS,
)
from litellm.litellm_core_utils.llm_cost_calc.utils import parse_prompt_tokens_details
from litellm.types.llms.openai import Batch
from litellm.types.utils import CallTypes, ModelInfo, Usage
Expand Down Expand Up @@ -507,6 +510,9 @@ def _extract_file_access_credentials(litellm_params: dict | None) -> dict:
"max_retries",
"_litellm_internal_model_credentials",
*AWS_CREDENTIAL_KWARGS_KEYS,
# A federated deployment holds no api_key, so without these the fetch that reads a
# finished batch's output has nothing to authenticate with and its cost is never billed.
*sorted(ANTHROPIC_WIF_KWARGS_KEYS),
)
for key in credential_keys:
if key in litellm_params:
Expand Down
2 changes: 2 additions & 0 deletions litellm/batches/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,13 +483,15 @@ def _handle_retrieve_batch_providers_without_provider_config(
)
api_key = optional_params.api_key or litellm.api_key or litellm.azure_key or get_secret_str("ANTHROPIC_API_KEY")

batch_params: Final = dict(litellm_params) # mutable-ok: handler contract, copied not shared
response = anthropic_batches_instance.retrieve_batch(
_is_async=_is_async,
batch_id=batch_id,
api_base=api_base,
api_key=api_key,
timeout=timeout,
max_retries=optional_params.max_retries,
litellm_params=batch_params,
)
else:
raise litellm.exceptions.BadRequestError(
Expand Down
48 changes: 47 additions & 1 deletion litellm/litellm_core_utils/get_litellm_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,54 @@
# The per-deployment Rust opt-in.
RUST_KWARG_KEY: Final = "rust"

# Anthropic workload identity federation config, read from litellm_params by the
# Anthropic auth tier. Registered like `rust`: here so the kwargs funnel carries
# them, and in `all_litellm_params` so they never leak into the provider body.
ANTHROPIC_WIF_KWARGS_KEYS: Final = frozenset(
{
"anthropic_federation_rule_id",
"anthropic_organization_id",
"anthropic_service_account_id",
"anthropic_workspace_id",
"anthropic_identity_token_file",
"anthropic_identity_token",
# Identity-source selection (Phase 1): absent means the legacy
# token_file/env resolver above, byte-identical to today.
"anthropic_identity_source",
# internal_issuer: litellm self-signs the workload assertion.
"anthropic_issuer_url",
"anthropic_issuer_subject",
"anthropic_issuer_audience",
"anthropic_issuer_ttl_seconds",
"anthropic_issuer_signing_key_ref",
# keycloak: litellm fetches the assertion via client_credentials.
"anthropic_keycloak_token_url",
"anthropic_keycloak_client_id",
"anthropic_keycloak_auth_method",
"anthropic_keycloak_client_secret_ref",
"anthropic_keycloak_scope",
# Set server-side when a client redirects api_base, to stop a federated deployment minting
# for a base the caller chose. It has to ride this funnel or it is dropped on the way and
# the deployment federates anyway; being carried here also request-bans it, which is right,
# since a caller must not be able to set it in either direction.
"anthropic_disable_workload_identity_federation",
}
)

OPENAI_WIF_KWARGS_KEYS: Final = frozenset(
{
"openai_identity_provider_id",
"openai_service_account_id",
"openai_identity_token_file",
}
)

# Keys `completion()` forwards from its own kwargs into `get_litellm_params`,
# which are otherwise invisible to it because that call site passes explicit
# named arguments rather than `**kwargs`.
FORWARDED_KWARGS_KEYS: Final = AWS_CREDENTIAL_KWARGS_KEYS | frozenset({RUST_KWARG_KEY})
FORWARDED_KWARGS_KEYS: Final = (
AWS_CREDENTIAL_KWARGS_KEYS | ANTHROPIC_WIF_KWARGS_KEYS | OPENAI_WIF_KWARGS_KEYS | frozenset({RUST_KWARG_KEY})
)

# Pre-define optional kwargs keys as frozenset for O(1) lookups
# These are extracted from kwargs only if present, avoiding unnecessary .get() calls
Expand Down Expand Up @@ -65,6 +109,8 @@
}
)
| AWS_CREDENTIAL_KWARGS_KEYS
| ANTHROPIC_WIF_KWARGS_KEYS
| OPENAI_WIF_KWARGS_KEYS
)

# Backward-compatible alias for existing imports/tests.
Expand Down
18 changes: 11 additions & 7 deletions litellm/llms/anthropic/batches/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ async def aretrieve_batch(
timeout: float | httpx.Timeout,
max_retries: int | None,
logging_obj: LiteLLMLoggingObj | None = None,
litellm_params: dict | None = None, # mutable-ok: handed straight to validate_environment
) -> LiteLLMBatch:
"""
Async: Retrieve a batch from Anthropic.
Expand All @@ -60,9 +61,7 @@ async def aretrieve_batch(
# Resolve API credentials
api_base = api_base or self.anthropic_model_info.get_api_base(api_base)
api_key = api_key or self.anthropic_model_info.get_api_key()

if not api_key:
raise ValueError("Missing Anthropic API Key")
resolved_litellm_params: Final = litellm_params if litellm_params is not None else {}

# Create a minimal logging object if not provided
if logging_obj is None:
Expand All @@ -85,16 +84,18 @@ async def aretrieve_batch(
api_base=api_base,
batch_id=batch_id,
optional_params={},
litellm_params={},
litellm_params=resolved_litellm_params,
)

# Validate environment and get headers
headers: Final = self.provider_config.validate_environment(
# Validate environment and get headers. Offloaded to a worker thread: a WIF token
# exchange here would otherwise block the event loop.
headers: Final = await asyncio.to_thread(
self.provider_config.validate_environment,
headers={},
model="",
messages=[],
optional_params={},
litellm_params={},
litellm_params=resolved_litellm_params,
api_key=api_key,
api_base=api_base,
)
Expand Down Expand Up @@ -130,6 +131,7 @@ def retrieve_batch(
timeout: float | httpx.Timeout,
max_retries: int | None,
logging_obj: LiteLLMLoggingObj | None = None,
litellm_params: dict | None = None, # mutable-ok: handed straight to validate_environment
) -> LiteLLMBatch | Coroutine[Any, Any, LiteLLMBatch]:
"""
Retrieve a batch from Anthropic.
Expand All @@ -154,6 +156,7 @@ def retrieve_batch(
timeout=timeout,
max_retries=max_retries,
logging_obj=logging_obj,
litellm_params=litellm_params,
)
else:
return asyncio.run(
Expand All @@ -164,5 +167,6 @@ def retrieve_batch(
timeout=timeout,
max_retries=max_retries,
logging_obj=logging_obj,
litellm_params=litellm_params,
)
)
28 changes: 18 additions & 10 deletions litellm/llms/anthropic/batches/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from litellm.types.llms.openai import AllMessageValues, CreateBatchRequest
from litellm.types.utils import LiteLLMBatch, LlmProviders, ModelResponse

from ..common_utils import merge_anthropic_beta_headers, without_caller_credential_headers

if TYPE_CHECKING:
import tiktoken

Expand Down Expand Up @@ -70,24 +72,30 @@ def validate_environment(
api_base: str | None = None,
) -> dict:
"""Validate and prepare environment-specific headers and parameters."""
if api_base is None and isinstance(litellm_params, dict):
api_base = litellm_params.get("api_base")
auth_header: Final = self.anthropic_model_info.get_auth_header(api_key, api_base)
params_mapping: Final = litellm_params if isinstance(litellm_params, dict) else None
if api_base is None and params_mapping is not None:
api_base = params_mapping.get("api_base")
auth_header: Final = self.anthropic_model_info.get_auth_header(
api_key, api_base, litellm_params=params_mapping, allow_workload_identity=True
)
if auth_header is None:
raise ValueError(
"Missing Anthropic API Key - A call is being made to anthropic but no key is set either in the environment variables or via params"
)
_headers: Final = {
merged_beta: Final = merge_anthropic_beta_headers(
merge_anthropic_beta_headers(headers.get("anthropic-beta"), auth_header.get("anthropic-beta")),
"message-batches-2024-09-24",
)
# The deployment's own credential is applied below, so a caller-supplied one must not
# ride along: without this a minted federation Bearer travels beside the caller's x-api-key.
return {
**without_caller_credential_headers(headers),
"accept": "application/json",
"anthropic-version": "2023-06-01",
"content-type": "application/json",
**auth_header,
"anthropic-beta": merged_beta,
}
_headers.update(auth_header)
# Add beta header for message batches
if "anthropic-beta" not in headers:
headers["anthropic-beta"] = "message-batches-2024-09-24"
headers.update(_headers)
return headers

def get_complete_batch_url(
self,
Expand Down
4 changes: 3 additions & 1 deletion litellm/llms/anthropic/chat/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import time
from collections.abc import Callable, Mapping, Sequence
from types import MappingProxyType
from typing import TYPE_CHECKING, Any, Final, NoReturn, cast
from typing import TYPE_CHECKING, Any, ClassVar, Final, NoReturn, cast

import httpx
from pydantic import ValidationError
Expand Down Expand Up @@ -284,6 +284,8 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
to pass metadata to anthropic, it's {"user_id": "any-relevant-information"}
"""

_workload_identity_eligible: ClassVar[bool] = True

max_tokens: int | None = None
stop_sequences: list | None = None
temperature: int | None = None
Expand Down
Loading
Loading