docs/en/guides/04-authentication.md
OpenViking Server supports three authentication modes with role-based access control: api_key, trusted, and dev. The mode is auto-detected if not explicitly configured.
OpenViking uses a two-layer API key system:
| Key Type | Created By | Role | Purpose |
|---|---|---|---|
| Root Key | Server config (root_api_key) | ROOT | Full access + admin operations |
| User Key | Admin API | ADMIN or USER | Per-account access |
All API keys are plain random tokens with no embedded identity. The server resolves identity by first comparing against the root key, then looking up the user key index.
| Mode | server.auth_mode | Identity Source | Typical Use |
|---|---|---|---|
| API key mode | "api_key" | API key, with optional tenant headers for root requests | Standard multi-tenant deployment |
| Trusted mode | "trusted" | X-OpenViking-Account / X-OpenViking-User / optional X-OpenViking-Agent, plus root_api_key on non-localhost deployments. Role is looked up from APIKeyManager if the user exists. | Behind a trusted gateway or internal network boundary |
| Dev mode | "dev" | No authentication, always ROOT | Local development only |
If auth_mode is not explicitly configured:
root_api_key is set (non-empty): auto-selects api_key moderoot_api_key is not set: auto-selects dev modeNote: Setting
root_api_keyto an empty string""is invalid. Either set a non-empty value or remove the setting entirely.
Configure the authentication mode in the server section of ov.conf:
{
"server": {
"auth_mode": "api_key",
"root_api_key": "your-secret-root-key"
}
}
Start the server:
openviking-server
Normal requests in both api_key and trusted modes do not need Admin API as a prerequisite for ordinary reads, writes, search, or session access. Admin API is still the place to create accounts, register users, change roles, and issue user keys.
Use the root key to create accounts (workspaces) and users via the Admin API:
# Create account with first admin
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "X-API-Key: your-secret-root-key" \
-H "Content-Type: application/json" \
-d '{"account_id": "acme", "admin_user_id": "alice"}'
# Returns: {"result": {"account_id": "acme", "admin_user_id": "alice", "user_key": "..."}}
# Register a regular user (as ROOT or ADMIN)
curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users \
-H "X-API-Key: your-secret-root-key" \
-H "Content-Type: application/json" \
-d '{"user_id": "bob", "role": "user"}'
# Returns: {"result": {"account_id": "acme", "user_id": "bob", "user_key": "..."}}
Trusted deployments can also call Admin API through a trusted gateway. There are two supported patterns:
root_api_key. For /api/v1/admin/*, the server treats the request as ROOT even without X-OpenViking-Account / X-OpenViking-User.X-OpenViking-Account + X-OpenViking-User for a registered gateway user. In that case the server looks up the effective role from the user registry.Example using a registered gateway user:
# First, register the gateway admin (do this once in api_key mode)
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "X-API-Key: your-secret-root-key" \
-H "Content-Type: application/json" \
-d '{"account_id": "platform", "admin_user_id": "gateway-admin"}'
# Then promote it to root if it needs cross-account admin access
curl -X PUT http://localhost:1933/api/v1/admin/accounts/platform/users/gateway-admin/role \
-H "X-API-Key: your-secret-root-key" \
-H "Content-Type: application/json" \
-d '{"role": "root"}'
# Then, in trusted mode, use that identity to call Admin API
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "X-API-Key: your-secret-root-key" \
-H "X-OpenViking-Account: platform" \
-H "X-OpenViking-User: gateway-admin" \
-H "Content-Type: application/json" \
-d '{
"account_id": "acme",
"admin_user_id": "alice",
"isolate_user_scope_by_agent": true,
"isolate_agent_scope_by_user": false
}'
OpenViking accepts API keys via two headers:
X-API-Key header
curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
-H "X-API-Key: <user-key>"
Authorization: Bearer header
curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
-H "Authorization: Bearer <user-key>"
Python SDK (HTTP)
import openviking as ov
client = ov.SyncHTTPClient(
url="http://localhost:1933",
api_key="<user-key>",
agent_id="my-agent"
)
CLI (via ovcli.conf)
{
"url": "http://localhost:1933",
"api_key": "<user-key>",
"account": "acme",
"user": "alice",
"agent_id": "my-agent"
}
When you use a regular user key, account and user are optional because the server can derive them from the key. They are recommended when you use trusted mode or a root key against tenant-scoped APIs.
CLI override flags
openviking --account acme --user alice --agent-id my-agent ls viking://
The CLI supports configuring both api_key (for regular user operations) and root_api_key (for admin operations) in ovcli.conf:
{
"url": "http://localhost:1933",
"api_key": "<user-key>",
"root_api_key": "<root-key>",
"account": "acme",
"user": "alice",
"agent_id": "my-agent"
}
When you need to perform admin commands (admin, system, reindex), use the --sudo flag to elevate privileges:
# List all accounts (requires root privileges)
ov --sudo admin list-accounts
# Reindex content
ov --sudo reindex viking://
# System commands
ov --sudo system status
The --sudo flag:
admin, system, reindexroot_api_key is not configured in ovcli.confroot_api_key instead of api_key for the requestWhen using the root key to access tenant-scoped data APIs (e.g. ls, find, sessions), you must specify the target account and user. The server will reject the request otherwise. Admin API and system status endpoints are not affected.
curl
curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
-H "X-API-Key: your-secret-root-key" \
-H "X-OpenViking-Account: acme" \
-H "X-OpenViking-User: alice"
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(
url="http://localhost:1933",
api_key="your-secret-root-key",
account="acme",
user="alice",
)
ovcli.conf
{
"url": "http://localhost:1933",
"api_key": "your-secret-root-key",
"account": "acme",
"user": "alice",
"agent_id": "my-agent"
}
Trusted mode skips user-key lookup and instead trusts explicit identity headers on each request:
{
"server": {
"auth_mode": "trusted",
"host": "127.0.0.1"
}
}
Rules in trusted mode:
X-OpenViking-Account and X-OpenViking-User are required on tenant-scoped requests.X-OpenViking-Agent is optional and defaults to default./api/v1/admin/* is special: when no explicit identity is provided, trusted mode treats the request as ROOT. This is intended for trusted upstreams that authenticate only with the deployment's root API key.USER.root_api_key is configured, it still acts as proof that the caller is an approved trusted upstream.root_api_key is also configured, every request must still provide a matching API key.Implications:
user_key from account creation and user registration results.root can create/delete accounts and change roles; admin can manage users inside its own account; user cannot call Admin API.curl
curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
-H "X-OpenViking-Account: acme" \
-H "X-OpenViking-User: alice" \
-H "X-OpenViking-Agent: my-agent"
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(
url="http://localhost:1933",
account="acme",
user="alice",
agent_id="my-agent",
)
When auth_mode = "dev" (or auto-detected when no root_api_key is configured), authentication is disabled. All requests are accepted as ROOT with the default account. This is only allowed when the server binds to localhost (127.0.0.1, localhost, or ::1). If host is set to a non-loopback address (e.g. 0.0.0.0) in dev mode, the server will refuse to start.
{
"server": {
"host": "127.0.0.1",
"port": 1933
}
}
Or explicitly:
{
"server": {
"auth_mode": "dev",
"host": "127.0.0.1",
"port": 1933
}
}
Security note: The default
hostis127.0.0.1. If you need to expose the server on the network, you must configureroot_api_key.
| Role | Scope | Capabilities |
|---|---|---|
| ROOT | Global | All operations + Admin API (create/delete accounts, manage users) |
| ADMIN | Own account | Regular operations + manage users in own account |
| USER | Own account | Regular operations (ls, read, find, sessions, etc.) |
In trusted mode, ordinary tenant requests default to USER unless the account/user is registered with a higher role. Admin routes also allow a trusted ROOT fallback when no explicit identity is provided.
The /health endpoint never requires authentication. This allows load balancers and monitoring tools to check server health.
curl http://localhost:1933/health
| Method | Endpoint | Role | Description |
|---|---|---|---|
| POST | /api/v1/admin/accounts | ROOT | Create account with first admin |
| GET | /api/v1/admin/accounts | ROOT | List all accounts |
| DELETE | /api/v1/admin/accounts/{id} | ROOT | Delete account |
| POST | /api/v1/admin/accounts/{id}/users | ROOT, ADMIN | Register user |
| GET | /api/v1/admin/accounts/{id}/users | ROOT, ADMIN | List users |
| DELETE | /api/v1/admin/accounts/{id}/users/{uid} | ROOT, ADMIN | Remove user |
| PUT | /api/v1/admin/accounts/{id}/users/{uid}/role | ROOT | Change user role |
| POST | /api/v1/admin/accounts/{id}/users/{uid}/key | ROOT, ADMIN | Regenerate user key |