--- title: Authentication description: How ClawMetry's HTTP surfaces authenticate — loopback by default, API tokens, the daemon query-server token, ingest tokens, OTLP auth and origin checks. keywords: clawmetry api token, agent API authentication, CLAWMETRY_API_TOKENS, ingest token eyebrow: HTTP API --- # Authentication Five surfaces, five different answers, because they carry different risk. ## The dashboard API **Default: loopback, no token.** The dashboard binds to `127.0.0.1` and anything that can reach it is already on the machine. To require a token: ```bash export CLAWMETRY_API_TOKENS=, ``` ```bash TOKEN= curl -s -H "Authorization: Bearer $TOKEN" localhost:8900/api/local/sessions ``` Comma-separated so you can rotate without downtime: add the new token, move clients over, remove the old one. Set this whenever anything other than your own browser calls the API, and always when the dashboard is reachable beyond loopback. ## The daemon's query server Always authenticated, with a token generated at startup and written to a discovery file: ```json title="~/.clawmetry/local_query.json" {"port": 51843, "token": "…", "pid": 4711} ``` ```bash PORT=$(jq -r .port ~/.clawmetry/local_query.json) TOK=$(jq -r .token ~/.clawmetry/local_query.json) curl -s "http://127.0.0.1:$PORT/api/local/query" \ -H "Authorization: Bearer $TOK" \ -H 'content-type: application/json' \ -d '{"shape":"sessions","args":{"limit":5}}' ``` The file is readable only by your user, and the token changes when the daemon restarts. Read it at call time rather than caching the value. Consumers should also check the pid is alive before trusting the port — a stale file from a crashed daemon would otherwise point at whatever process later took it. The MCP server does exactly this. ## The custom-runtime ingest API Two modes: 1. **Loopback only (default).** With `CLAWMETRY_INGEST_TOKEN` unset, only loopback requests are accepted. 2. **Token header.** Set it, and clients send `X-ClawMetry-Token: `. The comparison is constant-time. ```bash export CLAWMETRY_INGEST_TOKEN=secret curl -s localhost:8900/api/v1/runs \ -H "X-ClawMetry-Token: secret" \ -H 'content-type: application/json' \ -d '{"runtime":"my_engine"}' ``` A non-loopback request without a matching token returns `401`. Note the different header. Ingest uses `X-ClawMetry-Token` and read uses `Authorization: Bearer` — they are separate credentials with separate blast radii, and a write token should not be able to read your transcripts. ## OTLP The receivers accept untrusted data that lands in your store, so they are authenticated like any other write surface. For a local-only setup: ```bash CLAWMETRY_OTLP_ALLOW_UNAUTH=1 clawmetry ``` Do not set that on anything with a routable address. ## Control endpoints Pause, stop and kill are **origin-checked** rather than token-gated. They signal real processes, and the check exists to stop a cross-origin request from a page you happened to have open. They are not entitlement-gated: you pressed the button. If you put a reverse proxy in front, forward the origin correctly or those requests are refused — and that refusal is the correct behaviour. ## Self-hosted node ingest Nodes authenticate to a self-hosted endpoint with node tokens: ```bash export CLAWMETRY_API_TOKENS=node_a,node_b ``` → [Self-hosted ingest](/docs/cloud/self-hosted/) ## Cloud Node-to-cloud uses the API key from `clawmetry connect`, held in `~/.clawmetry/`. It authenticates the node; it does **not** decrypt anything — session content is encrypted with a separate key that never leaves the machine. ```bash clawmetry status --show-key # prints a credential to your terminal ``` → [End-to-end encryption](/docs/cloud/encryption/) ## Summary | Surface | Credential | Default | |---|---|---| | Dashboard API | `Authorization: Bearer` from `CLAWMETRY_API_TOKENS` | Loopback, none | | Daemon query server | Bearer token from `local_query.json` | Always required | | Custom ingest | `X-ClawMetry-Token` from `CLAWMETRY_INGEST_TOKEN` | Loopback only | | OTLP | Same as the dashboard API | Required unless explicitly allowed | | Control endpoints | Origin check | Always | | Node to cloud | API key from `connect` | — | ## What none of these are None of this is user authentication. There are no accounts, roles or per-user permissions on the local dashboard — a token holder can do everything a token holder can do. If you need per-user access control, put an authenticating proxy in front and manage identity there. RBAC and SSO exist as Enterprise features on the cloud side. → [Ports and networking](/docs/config/networking/) · [Plans](/docs/ops/plans/)