feat: optional Bearer-token authentication via API_TOKEN env var

Disabled by default (empty API_TOKEN). When set:
- All /api/* and /mcp requests require: Authorization: Bearer <token>
- Public exemptions: /, /healthz, /static/*, /auth-check
- Web UI: pre-flight /auth-check on load; shows token modal if required
- Token stored in sessionStorage, sent on every API request
- Mid-session 401s re-trigger the token modal
- MCP clients must pass the header: Authorization: Bearer <token>
Files changed:
- app/config.py: api_token field + API_TOKEN env var
- app/api/auth.py: Starlette BaseHTTPMiddleware for token enforcement
- main.py: register middleware + /auth-check public endpoint
- static/js/api.js: token storage, auth header, 401 handler hook
- static/js/app.js: auth pre-flight, showTokenModal(), bootstrap()
- static/css/components.css: .auth-overlay / .auth-card styles
- README.md: API_TOKEN env var docs + MCP client header example
This commit is contained in:
2026-03-27 04:28:12 +08:00
parent 1cc75afe87
commit 009fd039a2
7 changed files with 309 additions and 9 deletions

View File

@@ -492,6 +492,7 @@ Server-Sent Events endpoint for live UI updates.
- [x] MCP stateless/stateful mode configurable via `MCP_STATELESS` env var (default `true`).
- [x] Per-agent generation counter prevents abandoned (timed-out) coroutines from silently consuming instructions meant for newer calls.
- [x] `tests/test_wakeup.py` covers both immediate-wakeup timing and concurrent-call generation safety.
- [x] Optional Bearer-token authentication via `API_TOKEN` env var (disabled by default); web UI prompts for token on first load.
- [ ] **Documentation and developer experience**
- [x] Document local run instructions.
@@ -564,6 +565,7 @@ The server starts on `http://localhost:8000` by default.
| `DEFAULT_EMPTY_RESPONSE` | _(empty)_ | Default response when queue is empty |
| `AGENT_STALE_AFTER_SECONDS` | `30` | Seconds of inactivity before agent shown as idle |
| `MCP_STATELESS` | `true` | `true` for stateless sessions (survives restarts, recommended); `false` for stateful |
| `API_TOKEN` | _(empty)_ | When set, all `/api/*` and `/mcp` requests require `Authorization: Bearer <token>`; web UI prompts for the token on first load |
### Configuring an MCP client (agent)
@@ -580,6 +582,22 @@ Point the agent's MCP client to the streamable-HTTP transport:
}
```
If `API_TOKEN` is set, include the token as a request header:
```json
{
"mcpServers": {
"local-mcp": {
"url": "http://localhost:8000/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer <your-token>"
}
}
}
}
```
The agent should call `get_user_request` aggressively and continuously — **do not end the working session**. Every call returns the next pending instruction (if any). When the queue is empty the tool waits up to `wait_seconds` before returning an empty/default response, so the agent should loop and call again.
## 10. Implementation Notes for Future Work