Authentication and API keys
The HTTP API, the Runtime Lifecycle API, and the WebSocket API all use the same API key mechanism. API keys (also called ApiKeys) live in apikeys.json; each key carries a role that governs what it can do — across all three surfaces.
How it works
API keys are provided via the apikey HTTP header or the ?apikey= query parameter. The header is checked first; if empty, the query parameter is used as fallback.
# Header
curl -H "apikey: my-secret-key" http://localhost:8080/api/getstatistics
# Query parameter
curl http://localhost:8080/api/getstatistics?apikey=my-secret-key
Keys are validated against apikeys.json, located in the application directory (next to the executable).
apikeys.json format
apikeys.json accepts two forms, and the two can be mixed in one file.
Legacy form — each key is a bare string and gets full (admin) access. This is unchanged and still works exactly as before:
{
"Keys": [
"my-secret-key",
"another-key"
]
}
Scoped form — each key is an object that declares a role (and an optional descriptive label):
{
"Keys": [
{ "key": "abc123", "role": "operator", "label": "studio-panel" },
{ "key": "def456", "role": "viewer" },
{ "key": "ghi789", "role": "admin" }
]
}
Role resolution rules:
- A bare string, or an object with no
role, ⇒ admin (legacy full access). - An object with an unknown / garbage
rolestring fails closed to viewer — it is never silently promoted to admin. labelis optional and purely descriptive (handy for auditing which key is which).
A backup (apikeys.bak) is created automatically on startup. If apikeys.json is missing but apikeys.bak exists, the backup is restored. If neither file exists, an empty apikeys.json is created.
Roles & permissions
Each key maps to one of four roles — viewer, operator, editor, admin — that form a fixed ladder, where each higher role is a superset of the ones below it.
| Role | Grants |
|---|---|
viewer |
read |
operator |
read, control |
editor |
read, control, config, builder |
admin |
read, control, config, builder, admin (everything) |
What each permission covers:
- read — monitoring / inspection: statistics, get property, list objects, images / snapshots, status, capabilities, events / SSE, WebSocket monitoring subscriptions.
- control — operating the running engine: start, stop, exit, setproperty, invokecommand, switcher/*, layer/setsource, scene/disablerender, source reload / clear, media play, target executecommand, alarms/clear, and the WebSocket
SetPropertyValueByObjectId/ExecuteCommandByObjectIdmessages. - config — changing persisted project / settings, which can carry secrets: project save / load / upload, project setproperty, project getxml, settings get / getjson / set, scriptengine execute, connector trigger. Deliberately strict: settings reads and project-XML dumps require config (not read) because they can expose secrets such as stream keys.
- builder — entity CRUD: input / scene / layer / target / operator / connector create / delete / reorder / list, types/*, batch. These are also gated by the existing
EnableBuilderApisetting — the gate and this permission are checked independently, so enabling the Builder API does not grant a lesser key access. - admin — debug/, tests/, autotest set*, WebSocket disconnect / disconnectall, license/validate, discovery.
Each endpoint section below states its required permission (and the minimum role that grants it) with a Requires: note.
Validation behavior
Every request resolves to one of four outcomes, depending on whether the key is valid and whether its role covers the endpoint's required permission.
| Scenario | Result |
|---|---|
No keys defined (empty Keys array), or apikeys.json missing / unreadable |
Open mode — request proceeds as admin (unchanged legacy behavior) |
| Valid key whose role grants the endpoint's required permission | 200 — request proceeds |
| Valid key whose role does not grant the required permission | 403 Forbidden — the body / JSON states the required permission |
| Key provided but unknown / invalid | 401 Unauthorized — request rejected |
So: if you define keys, callers must provide a valid one and hold a role that covers the endpoint. If you don't define any keys, the API is open to all callers as admin. Key comparison is case-sensitive.
WebSocket authentication
The WebSocket API uses the same apikeys.json keys and the same roles. A client presents its key on the connection handshake — either as an ?apikey= query parameter on the WebSocket URL or an apikey header. When keys are defined and the RequireWebSocketAuth setting is enabled (the default), a missing or invalid key is rejected at connect time (the server sends an Error message and closes the socket). Once connected, per-message operations are gated by the connecting key's role: subscriptions require read, while the SetPropertyValueByObjectId and ExecuteCommandByObjectId messages require control. Setting RequireWebSocketAuth to false restores the pre-RBAC behaviour (any client may connect). Open mode (no keys defined) always connects as admin. See the WebSocket API for the full message-level details.