API Authentication in docling-serve#
Overview#
docling-serve implements optional API key authentication controlled by a single environment variable: DOCLING_SERVE_API_KEY. When unset (or empty), the server accepts all requests without authentication. When set, every request must present the correct secret .
The feature spans two transport mechanisms, each with its own credential delivery mechanism:
| Transport | Credential delivery |
|---|---|
| HTTP (all REST endpoints) | X-Api-Key request header |
WebSocket (/v1/status/ws/{task_id}) | api_key query parameter |
Configuration#
Set the environment variable before starting the server:
export DOCLING_SERVE_API_KEY=<your-secret>
docling-serve run
The setting maps to the api_key field in DoclingServeSettings (prefix DOCLING_SERVE_). An empty string ("") is treated as "auth disabled" — the _validate_api_key method short-circuits to valid when self.api_key == "".
The api_key setting can also be supplied via a YAML/JSON config file (DOCLING_SERVE_CONFIG_FILE). Priority order is: env var > config file > defaults .
HTTP Enforcement#
The APIKeyAuth class in docling_serve/auth.py extends FastAPI's APIKeyHeader to validate the X-Api-Key header. A single instance is created at app startup :
require_auth = APIKeyAuth(docling_serve_settings.api_key)
This dependency is injected via Depends(require_auth) on every protected endpoint, including:
POST /v1/convert/sourcePOST /v1/convert/filePOST /v1/convert/source/asyncPOST /v1/convert/source/batchPOST /v1/convert/file/asyncGET /v1/status/poll/{task_id}GET /v1/result/{task_id}- All
/v1/chunk/...and/v1/clear/...endpoints
Failure response: HTTP 401 Unauthorized. The check fires when api_key is non-empty and the header is missing or does not match .
Excluded from auth: /health, /ready, /version, /metrics, and the OpenAPI schema endpoints do not carry the require_auth dependency, so they remain publicly accessible.
WebSocket Enforcement#
The /v1/status/ws/{task_id} WebSocket endpoint cannot use standard HTTP headers after the handshake, so it accepts the key as a query parameter instead :
ws://host:5001/v1/status/ws/<task_id>?api_key=<secret>
The check is inline rather than via APIKeyAuth . The code comments note that query-parameter values may be captured in proxy and access logs — a known trade-off of the WebSocket transport.
Client Usage#
HTTP (curl):
curl -X POST http://localhost:5001/v1/convert/source \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <secret>' \
-d '{"sources": [{"kind": "http", "url": "https://example.com/doc.pdf"}]}'
Java SDK — the docling-serve-client builder accepts an .apiKey(String) method that injects the header automatically .
Key Source Files#
| File | Purpose |
|---|---|
docling_serve/auth.py | APIKeyAuth FastAPI dependency — header extraction and validation |
docling_serve/settings.py | api_key field in DoclingServeSettings |
docling_serve/app.py | require_auth instantiation and per-endpoint Depends(require_auth) |
docs/configuration.md | Official configuration table entry for DOCLING_SERVE_API_KEY |
docs/usage.md | Authentication usage note in API reference |