Skip to content

WebSocket auth rejects valid API keys containing URL-special characters — chat silently falls back to HTTP (no streaming) #962

@chrisyoung2005

Description

@chrisyoung2005

Description

The WebSocket upgrade handler in crates/openfang-api/src/ws.rs authenticates via a ?token= query parameter for browser clients (browsers cannot set custom headers on WebSocket connections). The handler extracts the token value with a raw split('&') / strip_prefix("token=") approach and compares it directly against the configured API key.

The bug: browsers call encodeURIComponent() on the token before appending it to the WebSocket URL (implemented in static/js/api.js). Characters common in base64-derived keys — +, /, = — are percent-encoded to %2B, %2F, %3D. The server receives the encoded string and compares it character-for-character against the raw key. They never match, so every WebSocket upgrade returns 401.

The fallback path in chat.js silently switches to HTTP polling mode with a toast notification ("Using HTTP mode (no streaming)"). The user sees responses arriving as complete messages rather than streaming tokens, with no clear indication that the root cause is an API key character encoding issue.

Affected users: any installation where the API key contains +, /, or = — this includes virtually all base64-derived keys (e.g., keys generated with openssl rand -base64 32). Keys using only alphanumeric characters and - / _ are not affected.

Workaround: generate an API key that contains only URL-safe characters (alphanumeric, -, _). Example: openssl rand -hex 32.

Expected Behavior

The chat dashboard uses WebSocket for all agent communication regardless of API key content. Streaming tokens appear in real time. User does not have to wait until entire response is formed to see its contents.

Steps to Reproduce

  1. Configure an API key containing +, /, or = (any base64-derived key):
    # Example key that triggers the bug:
    openssl rand -base64 32
    # → Zelrgr4sRcPzu4VNFcgbdykL02nT+h73l1mH3jlvjgZL9+QvlJ7uiBdZCs/gPwKz
  2. Set in environment: OPENFANG_API_KEY=<key above> with api_key = "" in config.toml
  3. Open the dashboard and navigate to any agent's chat view
  4. Send a message

Actual: toast notification "Using HTTP mode (no streaming)" appears; responses arrive as complete blocks; WebSocket connection never establishes.

Expected: WebSocket connects immediately on agent selection; responses stream token by token.

Debugging confirmation

Server-side the endpoint is reachable. A raw WebSocket upgrade with the literal (non-encoded) key succeeds (101 Switching Protocols). A request with encodeURIComponent-encoded token returns 401.

OpenFang Version

0.5.7

Operating System

Linux (x86_64)

Logs / Screenshots

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions