What happened?
LiteLLM proxy does not read authentication headers during WebSocket handshake for the /v1/realtime endpoint.
Actual Behavior
- WebSocket connection to
/v1/realtime is accepted
- Connection immediately closes with error 403: "No API key provided"
- Server logs show "Exception: No api key passed in" (3 times)
- Authentication headers (
Authorization, api-key) are completely ignored during WebSocket handshake
Expected Behavior
LiteLLM should read the authentication headers during WebSocket handshake and:
- Accept the client WebSocket connection ✅ (works)
- Validate the API key from headers ❌ (fails - headers not read)
- Forward the connection to OpenAI with proper authentication
- Maintain bidirectional WebSocket stream for real-time audio
- Track usage and apply quota management
Critical Finding
The same API key works perfectly for HTTP endpoints (/key/info, /v1/chat/completions) but fails for WebSocket connections. This proves:
- The API key is valid
- The issue is specific to WebSocket header handling
- Only the
/v1/realtime endpoint is affected (all HTTP endpoints work fine)
Reproduction Steps
1. LiteLLM Configuration (litellm_config.yaml):
model_list:
- model_name: gpt-realtime-mini
litellm_params:
model: openai/gpt-4o-realtime-preview
api_key: os.environ/OPENAI_API_KEY
files_settings:
- custom_llm_provider: openai
api_key: os.environ/OPENAI_API_KEY
2. Docker Compose setup:
services:
litellm:
image: ghcr.io/berriai/litellm:main-v1.80.11
environment:
- LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
ports:
- "4000:4000"
volumes:
- ./litellm_config.yaml:/app/config.yaml
3. Create a virtual API key via LiteLLM UI
4. Test HTTP authentication (to verify key is valid):
curl -X GET "https://your-server.com/key/info" \
-H "Authorization: Bearer sk-your-key"
Result: ✅ 200 OK - Returns key info (API key is valid)
5. Test WebSocket with same API key:
import asyncio
import websockets
async def test_realtime():
api_key = "sk-your-api-key-here" # Same key that works for HTTP
url = "wss://your-litellm-server.com/v1/realtime?model=gpt-realtime-mini"
# Try all authentication methods
headers = {
"Authorization": f"Bearer {api_key}",
"api-key": api_key,
"OpenAI-Beta": "realtime=v1"
}
async with websockets.connect(url, extra_headers=headers) as ws:
response = await ws.recv()
print(f"Received: {response}")
asyncio.run(test_realtime())
Result: ❌ WebSocket closes with 403 "No API key provided"
Root Cause Analysis
LiteLLM's WebSocket endpoint (/v1/realtime) cannot read custom HTTP headers during the WebSocket handshake.
Technical details:
- FastAPI/Starlette limitation: Custom headers (
Authorization, api-key) sent during WebSocket upgrade request are not accessible via the standard WebSocket API
- Authentication check location:
user_api_key_auth.py:632 in _user_api_key_auth_builder()
- LiteLLM tries to validate the key 3 times via
GET /key/info?key=sk-xxx but the key parameter is never extracted from headers
What works:
- ✅ HTTP authentication with
Authorization header (/key/info, /v1/chat/completions)
- ✅ Standard chat completions with streaming (SSE)
- ✅ Embeddings API
- ✅ All REST HTTP endpoints
What doesn't work:
- ❌ WebSocket
/v1/realtime with Authorization header
- ❌ WebSocket
/v1/realtime with api-key header
- ❌ Any combination of authentication headers in WebSocket handshake
Attempted workarounds (all failed):
- Multiple header formats:
Authorization, api-key, x-litellm-api-key - none are read
- WebSocket subprotocols: OpenAI-style
openai-insecure-api-key.{API_KEY} - not supported
- Different WebSocket client libraries - headers never reach LiteLLM auth layer
Related Issues
- #6825 - WebSocket issues with OpenAI Realtime API in browser (marked "not planned")
- #6926 -
/v1/realtime endpoint not checking API key (vulnerability fixed in v1.80.5, but headers still not working)
Environment
- OS: Linux (Docker container)
- Deployment: Docker Compose
- LiteLLM version: v1.80.11
- Docker image:
ghcr.io/berriai/litellm:main-v1.80.11
- Python: 3.13 (in container)
- websockets library: 13.1
- OpenAI API: Works correctly when accessed directly (bypassing LiteLLM confirms the issue is in LiteLLM, not upstream)
Relevant log output
INFO: 10.x.x.x:xxxxx - "GET /key/info?key=sk-xxxx HTTP/1.1" 401 Unauthorized
12:59:18 - LiteLLM Proxy:ERROR: auth_exception_handler.py:79 - litellm.proxy.proxy_server.user_api_key_auth(): Exception occured - No api key passed in.
Requester IP Address:10.x.x.x
Traceback (most recent call last):
File "/usr/lib/python3.13/site-packages/litellm/proxy/auth/user_api_key_auth.py", line 632, in _user_api_key_auth_builder
raise Exception("No api key passed in.")
Exception: No api key passed in.
INFO: 10.x.x.x:xxxxx - "GET /key/info?key=sk-xxxx HTTP/1.1" 401 Unauthorized
12:59:18 - LiteLLM Proxy:ERROR: auth_exception_handler.py:79 - litellm.proxy.proxy_server.user_api_key_auth(): Exception occured - No api key passed in.
Requester IP Address:10.x.x.x
Traceback (most recent call last):
File "/usr/lib/python3.13/site-packages/litellm/proxy/auth/user_api_key_auth.py", line 632, in _user_api_key_auth_builder
raise Exception("No api key passed in.")
Exception: No api key passed in.
INFO: 10.x.x.x:xxxxx - "GET /key/info?key=sk-xxxx HTTP/1.1" 401 Unauthorized
12:59:18 - LiteLLM Proxy:ERROR: auth_exception_handler.py:79 - litellm.proxy.proxy_server.user_api_key_auth(): Exception occured - No api key passed in.
Requester IP Address:10.x.x.x
Traceback (most recent call last):
File "/usr/lib/python3.13/site-packages/litellm/proxy/auth/user_api_key_auth.py", line 632, in _user_api_key_auth_builder
raise Exception("No api key passed in.")
Exception: No api key passed in.
INFO: ('10.x.x.x', xxxxx) - "WebSocket /v1/realtime?model=gpt-realtime-mini" [accepted]
INFO: connection open
INFO: connection closed
What part of LiteLLM is this about?
Proxy
What LiteLLM version are you on ?
v1.80.11
Twitter / LinkedIn details
No response
What happened?
LiteLLM proxy does not read authentication headers during WebSocket handshake for the
/v1/realtimeendpoint.Actual Behavior
/v1/realtimeis acceptedAuthorization,api-key) are completely ignored during WebSocket handshakeExpected Behavior
LiteLLM should read the authentication headers during WebSocket handshake and:
Critical Finding
The same API key works perfectly for HTTP endpoints (
/key/info,/v1/chat/completions) but fails for WebSocket connections. This proves:/v1/realtimeendpoint is affected (all HTTP endpoints work fine)Reproduction Steps
1. LiteLLM Configuration (
litellm_config.yaml):2. Docker Compose setup:
3. Create a virtual API key via LiteLLM UI
4. Test HTTP authentication (to verify key is valid):
Result: ✅ 200 OK - Returns key info (API key is valid)
5. Test WebSocket with same API key:
Result: ❌ WebSocket closes with 403 "No API key provided"
Root Cause Analysis
LiteLLM's WebSocket endpoint (
/v1/realtime) cannot read custom HTTP headers during the WebSocket handshake.Technical details:
Authorization,api-key) sent during WebSocket upgrade request are not accessible via the standard WebSocket APIuser_api_key_auth.py:632in_user_api_key_auth_builder()GET /key/info?key=sk-xxxbut the key parameter is never extracted from headersWhat works:
Authorizationheader (/key/info,/v1/chat/completions)What doesn't work:
/v1/realtimewithAuthorizationheader/v1/realtimewithapi-keyheaderAttempted workarounds (all failed):
Authorization,api-key,x-litellm-api-key- none are readopenai-insecure-api-key.{API_KEY}- not supportedRelated Issues
/v1/realtimeendpoint not checking API key (vulnerability fixed in v1.80.5, but headers still not working)Environment
ghcr.io/berriai/litellm:main-v1.80.11Relevant log output
What part of LiteLLM is this about?
Proxy
What LiteLLM version are you on ?
v1.80.11
Twitter / LinkedIn details
No response