Skip to content

agent-server: support WebSocket auth via headers#1814

Open
enyst wants to merge 13 commits intomainfrom
openhands/agent-server-ws-header-auth
Open

agent-server: support WebSocket auth via headers#1814
enyst wants to merge 13 commits intomainfrom
openhands/agent-server-ws-header-auth

Conversation

@enyst
Copy link
Collaborator

@enyst enyst commented Jan 24, 2026

HUMAN: I apologize for my little agent team. 🙏 They had a security audit and became very stressed about the api key in query string, so they came upstream to fix it (I didn’t know!), and started pinging maintainers to merge their PR. (previous version of this PR 🫣)

… The future is wild. 😂

The main proposal here is minimally: allow for the session key to be sent in headers too. URL param still takes precedence.

—-

Hi! I’m OpenHands (an automated AI software engineering agent) contributing this PR.

Summary

Enable WebSocket authentication via HTTP headers in the OpenHands agent server, keeping behavior consistent with REST auth.

Why

Some clients/proxies make it easier (or only possible) to pass auth in headers rather than query params. Supporting headers improves interoperability and avoids leaking tokens via URLs.

Changes

  • Accept WS auth via headers (aligned with existing REST behavior)
  • Keep browser compatibility via session_api_key query param (which takes precedence)
  • Ensure WS endpoints honor the Config passed to create_app(config) (via app.state.config)
  • Add/adjust tests covering:
    • header-based WS auth
    • precedence rules
    • wsproto integration (server started via spawn so env-based auth is deterministic)

Testing

  • pytest tests/agent_server/test_api_authentication.py::test_api_websocket_authentication
  • pytest tests/agent_server/test_agent_server_wsproto.py

Notes

  • Auth precedence is explicitly tested to prevent regressions.

Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.12-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:7341ad0-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-7341ad0-python \
  ghcr.io/openhands/agent-server:7341ad0-python

All tags pushed for this build

ghcr.io/openhands/agent-server:7341ad0-golang-amd64
ghcr.io/openhands/agent-server:7341ad0-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:7341ad0-golang-arm64
ghcr.io/openhands/agent-server:7341ad0-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:7341ad0-java-amd64
ghcr.io/openhands/agent-server:7341ad0-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:7341ad0-java-arm64
ghcr.io/openhands/agent-server:7341ad0-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:7341ad0-python-amd64
ghcr.io/openhands/agent-server:7341ad0-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-amd64
ghcr.io/openhands/agent-server:7341ad0-python-arm64
ghcr.io/openhands/agent-server:7341ad0-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-arm64
ghcr.io/openhands/agent-server:7341ad0-golang
ghcr.io/openhands/agent-server:7341ad0-java
ghcr.io/openhands/agent-server:7341ad0-python

About Multi-Architecture Support

  • Each variant tag (e.g., 7341ad0-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., 7341ad0-python-amd64) are also available if needed

enyst and others added 6 commits January 24, 2026 08:02
Support X-Session-API-Key and Authorization: Bearer for WebSocket clients (query param remains for browser clients).

This unblocks oh-tab-h3g (stop leaking session_api_key in WS URLs).
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: OpenHands Bot <contact@all-hands.dev>
Co-authored-by: OpenHands Bot <contact@all-hands.dev>
@github-actions
Copy link
Contributor

github-actions bot commented Jan 24, 2026

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-agent-server/openhands/agent_server
   api.py1571292%71, 83, 98, 104, 264, 267, 271–273, 275, 281, 322
   dependencies.py22195%51
   sockets.py1142082%98, 103–105, 156–158, 164–166, 171–172, 174–175, 200–204, 214
TOTAL18279827354% 

Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this is a solid implementation that adds header-based WebSocket auth while maintaining backward compatibility. The code is well-structured, the auth precedence logic is clear and tested, and the deduplication of auth code is a nice improvement. I have a few minor suggestions for improving debuggability and test coverage.

enyst and others added 6 commits January 24, 2026 08:09
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
@enyst enyst requested a review from tofarr January 28, 2026 14:54
@all-hands-bot
Copy link
Collaborator

[Automatic Post]: This PR seems to be currently waiting for review. @tofarr, could you please take a look when you have a chance?

@all-hands-bot
Copy link
Collaborator

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

1 similar comment
@all-hands-bot
Copy link
Collaborator

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@enyst enyst requested a review from all-hands-bot February 13, 2026 23:14
Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taste Rating: 🟢 Good taste - Elegant, simple solution

This PR solves a real problem (header-based auth for non-browser clients) with a clean implementation. The refactoring centralizes auth logic, eliminates duplication, and maintains perfect backward compatibility with explicit precedence rules.

Key strengths:

  • Data flow is clean: query param > header precedence is straightforward
  • No complexity issues: functions are focused, <3 levels of indentation
  • Tests are solid: real WebSocket connections testing actual behavior, not mocks
  • Security is correct: no key logging, appropriate close codes (4001)
  • Breaking change risk: zero - query param still works and takes precedence

Verdict: ✅ Worth merging - fundamentally sound implementation

Key insight: The auth centralization eliminates special cases while maintaining browser compatibility through precedence rules rather than branching logic.

@enyst enyst added behavior-initiative This is related to the system prompt sections and LLM steering. and removed behavior-initiative This is related to the system prompt sections and LLM steering. labels Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants