feat(api): require api_key when binding to all interfaces (parity with WS gateway)

The OpenAI-compatible API server had no authentication option, unlike the
WebSocket gateway which already refuses wildcard binds without a token.
When bound to 0.0.0.0, any caller who could reach the port could drive
the agent with its default tool posture.

- Add api_key field to ApiConfig (schema.py).
- Add wildcard_host_requires_auth validator that rejects wildcard binds
  without api_key, mirroring the WS gateway pattern.
- Add Bearer-token auth middleware to the API server (server.py).
  /health remains unauthenticated.
- Replace the wildcard-host CLI warning with a hard error when api_key
  is unset, and pass api_key to create_app.

Fixes #4490
@
This commit is contained in:
dajiaohuang
2026-07-01 13:09:49 +08:00
committed by Xubin Ren
parent 21aa900d64
commit 56443ac6e2
3 changed files with 52 additions and 4 deletions
+13 -3
View File
@@ -798,14 +798,24 @@ def serve(
console.print(f" [cyan]Model[/cyan] : {model_name}{preset_tag}")
console.print(" [cyan]Session[/cyan] : api:default")
console.print(f" [cyan]Timeout[/cyan] : {timeout}s")
api_key = api_cfg.api_key.strip() if api_cfg.api_key else ""
if host in {"0.0.0.0", "::"}:
if not api_key:
console.print(
"[red]Error: host is 0.0.0.0 (all interfaces) but api_key is not set. "
"Set api.api_key in config to prevent unauthenticated access.[/red]"
)
raise typer.Exit(1)
console.print(
"[yellow]Warning:[/yellow] API is bound to all interfaces. "
"Only do this behind a trusted network boundary, firewall, or reverse proxy."
"[yellow]API is bound to all interfaces "
"(authentication required).[/yellow]"
)
console.print()
api_app = create_app(agent_loop, model_name=model_name, request_timeout=timeout)
api_app = create_app(
agent_loop, model_name=model_name, request_timeout=timeout,
api_key=api_key,
)
async def on_startup(_app):
await agent_loop._connect_mcp()