From 28141ce20bb6fbf186c875f2cc407dff8bc19007 Mon Sep 17 00:00:00 2001 From: chengyongru Date: Tue, 7 Jul 2026 16:32:28 +0800 Subject: [PATCH] docs: update serve api key requirement maintainer edit: Align OpenAI-compatible API docs and examples with the new fail-closed api.api_key requirement while keeping /health documented as unauthenticated. --- SECURITY.md | 2 +- docs/cli-reference.md | 2 ++ docs/openai-api.md | 28 ++++++++++++++++++---------- nanobot/api/server.py | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index e126d36a..436496e0 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -107,7 +107,7 @@ File operations have path traversal protection, but: **API Calls:** - All external API calls use HTTPS by default - Timeouts are configured to prevent hanging requests -- The OpenAI-compatible API server must set `api.api_key` when binding to `0.0.0.0` or `::`; otherwise startup fails to prevent unauthenticated network access +- The OpenAI-compatible API server requires `api.api_key` for API routes; only `/health` remains unauthenticated for probes and load balancers - Consider using a firewall to restrict outbound connections if needed **WhatsApp:** diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 415161d1..fc69ffe9 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -204,6 +204,8 @@ Default API endpoint: http://127.0.0.1:8900 ``` +`nanobot serve` requires `api.apiKey`; send it as a Bearer token on API routes. + See [`openai-api.md`](./openai-api.md) for request examples. ## Status diff --git a/docs/openai-api.md b/docs/openai-api.md index f31e7e42..062ead39 100644 --- a/docs/openai-api.md +++ b/docs/openai-api.md @@ -5,33 +5,32 @@ nanobot can expose a minimal OpenAI-compatible endpoint for local integrations: ```bash nanobot plugins enable api nanobot agent -m "Hello!" +# Set api.apiKey first; see Authentication below. nanobot serve ``` -Run the CLI check first. If `nanobot agent -m "Hello!"` fails, fix provider or config setup before debugging the API server. By default, the API binds to `127.0.0.1:8900`. You can change this in `config.json`. +Run the CLI check first. If `nanobot agent -m "Hello!"` fails, fix provider or config setup before debugging the API server. By default, the API binds to `127.0.0.1:8900`. You can change this in `config.json`. `nanobot serve` requires `api.apiKey`; set it before starting the server. For setup help, see [`quick-start.md`](./quick-start.md), [`providers.md`](./providers.md), and [`troubleshooting.md`](./troubleshooting.md). ## Authentication -Local-only `127.0.0.1` usage does not require an API key. If you bind the API -server to all interfaces with `api.host: "0.0.0.0"` or `"::"`, nanobot requires -`api.apiKey`; otherwise startup fails to avoid exposing an unauthenticated agent -endpoint on the network. +`nanobot serve` requires `api.apiKey` for all API binds. Without it, startup +fails before the agent is initialized. Keep the key secret and send it as a +Bearer token on API routes. ```json { "api": { - "host": "0.0.0.0", + "host": "127.0.0.1", "port": 8900, "apiKey": "${NANOBOT_API_KEY}" } } ``` -When `api.apiKey` is set, send it as a Bearer token on API routes. The health -endpoint remains unauthenticated so local probes and load balancers can still -check process health. +The health endpoint remains unauthenticated so local probes and load balancers +can still check process health. ```bash curl http://127.0.0.1:8900/v1/models \ @@ -70,6 +69,7 @@ If `channel` points to a channel that is not enabled in your config, nanobot wil ```bash curl http://127.0.0.1:8900/v1/chat/completions \ -H "Content-Type: application/json" \ + -H "Authorization: Bearer $NANOBOT_API_KEY" \ -d '{ "messages": [{"role": "user", "content": "hi"}], "session_id": "my-session" @@ -83,6 +83,7 @@ Send images inline using the OpenAI multimodal content format: ```bash curl http://127.0.0.1:8900/v1/chat/completions \ -H "Content-Type: application/json" \ + -H "Authorization: Bearer $NANOBOT_API_KEY" \ -d '{ "messages": [{"role": "user", "content": [ {"type": "text", "text": "Describe this image"}, @@ -98,11 +99,13 @@ Upload any supported file type (images, PDF, Word, Excel, PPT) via multipart: ```bash # Single file curl http://127.0.0.1:8900/v1/chat/completions \ + -H "Authorization: Bearer $NANOBOT_API_KEY" \ -F "message=Summarize this report" \ -F "files=@report.docx" # Multiple files with session isolation curl http://127.0.0.1:8900/v1/chat/completions \ + -H "Authorization: Bearer $NANOBOT_API_KEY" \ -F "message=Compare these files" \ -F "files=@chart.png" \ -F "files=@data.xlsx" \ @@ -117,10 +120,13 @@ Supported file types: ## Python (`requests`) ```python +import os + import requests resp = requests.post( "http://127.0.0.1:8900/v1/chat/completions", + headers={"Authorization": f"Bearer {os.environ['NANOBOT_API_KEY']}"}, json={ "messages": [{"role": "user", "content": "hi"}], "session_id": "my-session", # optional: isolate conversation @@ -134,11 +140,13 @@ print(resp.json()["choices"][0]["message"]["content"]) ## Python (`openai`) ```python +import os + from openai import OpenAI client = OpenAI( base_url="http://127.0.0.1:8900/v1", - api_key="dummy", + api_key=os.environ["NANOBOT_API_KEY"], ) resp = client.chat.completions.create( diff --git a/nanobot/api/server.py b/nanobot/api/server.py index e41f8a71..2dbef858 100644 --- a/nanobot/api/server.py +++ b/nanobot/api/server.py @@ -404,7 +404,7 @@ def create_app( agent_loop: An initialized AgentLoop instance. model_name: Model name reported in responses. request_timeout: Per-request timeout in seconds. - api_key: Optional API key for Bearer-token authentication. + api_key: API key for Bearer-token authentication on API routes. """ app = web.Application(client_max_size=20 * 1024 * 1024) # 20MB for base64 images app["agent_loop"] = agent_loop