BerriAI/litellm · error · HTTPException
Microsoft Purview DLP: No proxy-authenticated user identity;
Error message
Microsoft Purview DLP: No proxy-authenticated user identity; bind user_id to the API key (caller-supplied metadata cannot be used for blocking DLP)
What it means
Fail-closed HTTPException from Purview blocking-mode identity resolution. A user identity WAS found, but only via caller-influenceable fields (metadata.user_id, safety_identifier, per-request metadata[user_id_field]). Because those let any caller impersonate another Entra user's Purview policy, blocking DLP refuses them and demands an identity bound to the API key on the proxy side.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py:360
user_api_key_dict: Any,
) -> str:
"""Resolve user ID for blocking (pre_call / post_call) DLP hooks.
Uses only trusted proxy-authenticated sources (``_resolve_trusted_user_id``).
Caller-supplied ``UserAPIKeyAuth.end_user_id`` (from request ``user``,
``metadata.user_id``, ``safety_identifier``, etc.) and
``metadata[user_id_field]`` are rejected (fail closed) because they can
impersonate another Entra user's Purview policy.
Raises ``HTTPException`` when no API-key-bound ``user_id`` exists or when
only caller-influenceable identity fields are available (fail closed).
"""
trusted_id: Final = self._resolve_trusted_user_id(data, user_api_key_dict)
if trusted_id:
return trusted_id
if self._resolve_user_id(data, user_api_key_dict):
raise HTTPException(
status_code=400,
detail={
"error": (
"Microsoft Purview DLP: No proxy-authenticated user identity; "
"bind user_id to the API key (caller-supplied metadata cannot "
"be used for blocking DLP)"
),
},
)
raise HTTPException(
status_code=400,
detail={
"error": (
"Microsoft Purview DLP: No proxy-authenticated user identity; "
"bind user_id to the API key for blocking DLP"
),
},View on GitHub (pinned to 77b7c6c40c)
Solutions
- Bind the user to the virtual key at key-creation time: POST /key/generate with user_id (or /key/update for existing keys)
- With SSO/OIDC auth enabled, send requests with the logged-in session so user identity comes from proxy authentication, not the body
- After binding, stop relying on body-supplied user fields for these requests — they are deliberately ignored for blocking DLP
Example fix
# before: identity only in request body
client = OpenAI(api_key=VIRTUAL_KEY)
client.chat.completions.create(model="gpt-4o", messages=msgs, user="alice@corp.com")
# after: bind identity to the key, send plain request
# curl -X POST $PROXY/key/generate -H "Authorization: Bearer $ADMIN" \
# -d '{"user_id": "alice@corp.com", "models": ["gpt-4o"], ...}'
client = OpenAI(api_key=ALICE_BOUND_KEY)
client.chat.completions.create(model="gpt-4o", messages=msgs) Defensive patterns
Strategy: validation
Validate before calling
# Admin-side precheck: does this virtual key carry a bound user?
import httpx
def key_has_bound_user(proxy_url: str, key: str, admin_key: str) -> bool:
info = httpx.get(
f"{proxy_url}/key/info", params={"key": key},
headers={"Authorization": f"Bearer {admin_key}"},
).json()
return bool(info.get("key_info", {}).get("user_id")) Try / catch
try:
r = guarded_client.chat.completions.create(**params)
except BadRequestError as e:
if "bind user_id to the API key" in str(e):
# stop sending body-level user ids; provision a bound key instead
raise ProvisioningError("route requires key-bound identity")
raise Prevention
- Provision per-user virtual keys via /key/generate with user_id as part of onboarding, not as a reaction to this error
- Never rely on request-body user/metadata fields for identity on guarded routes — they are intentionally distrusted
- With SSO enabled, prefer session-authenticated calls so identity comes from proxy auth
When it happens
Trigger: Client sends 'user' or metadata.user_id in the /chat/completions body while the virtual key used has no bound user; per-request user param set but the key was created without user_id; only header-injected metadata supplies identity
Common situations: Migrating from another guardrail that trusted request-supplied user ids; teams relying on 'user' field for attribution suddenly adding Purview; SSO-less deployments where every caller shares one admin key
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Microsoft Purview DLP: No proxy-authenticated user identity;
- Microsoft Purview DLP: Responses API input could not be tran
- Microsoft Purview DLP: Token-id completion prompts cannot be
- Invalid API key
- Microsoft Purview: tenant_id is required
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/78897cd2928b2498.
Report an issue: GitHub.