Problem
ft serve exposes its HTTP API with no authentication:
python/freetoken/shell/client.py:31 sets LOCAL_API_KEY = "freetoken-local" with the comment "Any string is accepted by the server; sent so the SDK doesn't refuse to build a request."
server/api_server.py performs no api_key/Bearer validation on any route.
HERMES_API_KEY in server/launch.py is only consumed in shell mode, never enforced by the serve API.
On a multi-user machine, or whenever the port is forwarded beyond loopback, anyone who can reach the port can drive the full API (/v1/chat/completions, /generate, /v1/cache/rebuild, ...) and evict/rebuild KV state.
Proposal
--api-key <key> serve flag, plus FREETOKEN_API_KEY env fallback (flag wins).
- When set: require
Authorization: Bearer <key> on /v1/* and /generate; reject with 401 + the standard JSON error shape.
- Keep
GET /health open by default (orchestrators poll it before the model is ready; an --api-key-strict variant could lock it too).
- When unset: today's behavior, fully backward compatible.
Precedent
- vLLM:
--api-key / VLLM_API_KEY
- SGLang:
--api-key
- llama.cpp server:
--api-key
Context
Orchestrators and process managers that front multiple engine children typically mint a per-child token for each loopback listener; today that contract has to be enforced purely by network topology. A native flag makes the boundary explicit and cheap.
Happy to send a PR if the maintainers are open to it — the change looks contained to server/args.py + an auth dependency in server/api_server.py.
Problem
ft serveexposes its HTTP API with no authentication:python/freetoken/shell/client.py:31setsLOCAL_API_KEY = "freetoken-local"with the comment "Any string is accepted by the server; sent so the SDK doesn't refuse to build a request."server/api_server.pyperforms noapi_key/Bearervalidation on any route.HERMES_API_KEYinserver/launch.pyis only consumed in shell mode, never enforced by the serve API.On a multi-user machine, or whenever the port is forwarded beyond loopback, anyone who can reach the port can drive the full API (
/v1/chat/completions,/generate,/v1/cache/rebuild, ...) and evict/rebuild KV state.Proposal
--api-key <key>serve flag, plusFREETOKEN_API_KEYenv fallback (flag wins).Authorization: Bearer <key>on/v1/*and/generate; reject with401+ the standard JSON error shape.GET /healthopen by default (orchestrators poll it before the model is ready; an--api-key-strictvariant could lock it too).Precedent
--api-key/VLLM_API_KEY--api-key--api-keyContext
Orchestrators and process managers that front multiple engine children typically mint a per-child token for each loopback listener; today that contract has to be enforced purely by network topology. A native flag makes the boundary explicit and cheap.
Happy to send a PR if the maintainers are open to it — the change looks contained to
server/args.py+ an auth dependency inserver/api_server.py.