Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,14 @@ This page contains example commands to help you choose models and configure Open
--load-models model1 model2
```

To require API key authentication:

```
openarc serve start --use-api-key
```

When `--use-api-key` is passed, clients must authenticate with a `Bearer` token matching `OPENARC_API_KEY`. If the environment variable is not set, the server will not start. Without the flag, no authentication is required.

=== "load"

After using `openarc add` you can use `openarc load` to read the added configuration and load models onto the OpenArc server.
Expand Down
14 changes: 10 additions & 4 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ Visit [OpenVINO System Requirments](https://docs.openvino.ai/2025/about-openvino
uv pip install --pre -U openvino-genai --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly
```

4. Set your API key as an environment variable:
4. Optionally, set an API key to authenticate clients connecting to the server:
```
export OPENARC_API_KEY=api-key
```

Pass `--use-api-key` to `openarc serve start` to enforce authentication. See [serve](commands.md#serve) for details.

5. To get started, run:

```
Expand Down Expand Up @@ -70,11 +72,13 @@ Visit [OpenVINO System Requirments](https://docs.openvino.ai/2025/about-openvino
uv pip install --pre -U openvino-genai --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly
```

4. **Set your API key as an environment variable:**
4. **Optionally, set an API key to authenticate clients connecting to the server:**
```
setx OPENARC_API_KEY openarc-api-key
```

Pass `--use-api-key` to `openarc serve start` to enforce authentication. See [serve](commands.md#serve) for details.

5. To get started, run:

```
Expand Down Expand Up @@ -103,11 +107,13 @@ Visit [OpenVINO System Requirments](https://docs.openvino.ai/2025/about-openvino
Environment Variables

```bash
export OPENARC_API_KEY="openarc-api-key" # default, set it to whatever you want
export OPENARC_API_KEY="openarc-api-key" # optional — pass --use-api-key to openarc serve start to enforce
export OPENARC_AUTOLOAD_MODEL="model_name" # model_name to load on startup
export MODEL_PATH="/path/to/your/models" # mount your models to `/models` inside the container
docker-compose up --build -d
```
```

Pass `--use-api-key` to `openarc serve start` to require clients to authenticate. See [serve](commands.md#serve) for details.


Take a look at the [Dockerfile](Dockerfile) and [docker-compose](docker-compose.yaml) for more details.
Expand Down
14 changes: 13 additions & 1 deletion src/cli/groups/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ def serve():
@click.option("--load-models", "--lm",
required=False,
help="Load models on startup. Specify once followed by space-separated model names.")
@click.option("--use-api-key", is_flag=True, default=False,
help="Require OPENARC_API_KEY for all requests.")
@click.argument('startup_models', nargs=-1, required=False)
@click.pass_context
def start(ctx, host, port, load_models, startup_models):
def start(ctx, host, port, load_models, use_api_key, startup_models):
"""
- 'start' reads --host and --port from config or defaults to 0.0.0.0:8000

Expand Down Expand Up @@ -68,5 +70,15 @@ def start(ctx, host, port, load_models, startup_models):
os.environ["OPENARC_STARTUP_MODELS"] = ",".join(models_to_load)
console.print(f"[blue]Models to load on startup:[/blue] {', '.join(models_to_load)}\n")

if use_api_key:
if not os.getenv("OPENARC_API_KEY"):
console.print("[red]Error: You chose to require an API key but OPENARC_API_KEY has not been set.[/red]")
raise SystemExit(1)
os.environ["OPENARC_API_KEY_REQUIRED"] = "true"
console.print("[blue]OPENARC_API_KEY_REQUIRED=[/blue][green]True[/green] [dim][Clients connecting to the server must authenticate with OPENARC_API_KEY][/dim]")
else:
os.environ["OPENARC_API_KEY_REQUIRED"] = "false"
console.print("[blue]OPENARC_API_KEY_REQUIRED=[/blue][yellow]False[/yellow] [dim][Clients do not need to authenticate.][/dim]")

console.print(f"[green]Starting OpenArc server on {host}:{port}[/green]")
start_server(host=host, port=port)
11 changes: 7 additions & 4 deletions src/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,16 @@ async def lifespan(app: FastAPI):
except Exception as e:
logger.error(f"Startup: failed to load '{name}': {e}")

logger.info(f"OPENARC_API_KEY_REQUIRED={AUTH_REQUIRED}")
yield
# Shutdown: (add cleanup here if needed)

app = FastAPI(lifespan=lifespan)

# API key authentication
API_KEY = os.getenv("OPENARC_API_KEY")
security = HTTPBearer()
AUTH_REQUIRED = os.getenv("OPENARC_API_KEY_REQUIRED", "false").lower() == "true"
security = HTTPBearer(auto_error=False)

# Add request logging middleware (before CORS so it logs all requests)
app.add_middleware(RequestLoggingMiddleware)
Expand All @@ -120,14 +122,15 @@ async def lifespan(app: FastAPI):

async def verify_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)):
"""Verify the API key provided in the Authorization header"""
if credentials.credentials != API_KEY:
logger.error(f"Invalid API key: {credentials.credentials}")
if not AUTH_REQUIRED:
return None
if credentials is None or credentials.credentials != API_KEY:
logger.error(f"Invalid API key: {credentials.credentials if credentials else 'missing'}")
raise HTTPException(
status_code=401,
detail="Invalid API key",
headers={"WWW-Authenticate": "Bearer"},
)

return credentials.credentials

@app.exception_handler(RequestValidationError)
Expand Down