> For the complete documentation index, see [llms.txt](https://fleet.hackmap.win/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fleet.hackmap.win/operations/auth.md).

# Authentication

Two bearer tokens. Three endpoint categories. No TLS by default — you put a reverse proxy in front if you need it.

## Tokens

`FLEET_ADMIN_TOKEN` — full control. Read and patch any worker's config, pop any output stream, see any stats. Don't share, don't commit, rotate on compromise.

`FLEET_WORKER_TOKEN` — limited to worker-facing endpoints: the HTTP config poll and the WebSocket control channel. A worker token can read configs and push state/stats/output frames for any worker\_id. It cannot patch configs or pop streams.

Both tokens are shared across the fleet. There's no per-worker key. A compromised worker can impersonate any other worker (push fake outputs, fake stats), but it cannot escalate to admin. Per-worker keys are on the roadmap.

If you don't set these in the environment, the master generates random tokens at startup and prints them to stdout. This is fine for a smoke test. Fine for nothing else. Set them explicitly anywhere you care about state surviving a master restart, because the auto-generated tokens rotate every restart and break worker auth.

```bash
export FLEET_ADMIN_TOKEN=$(openssl rand -hex 32)
export FLEET_WORKER_TOKEN=$(openssl rand -hex 32)
```

## Endpoint matrix

| Endpoint                                               | Required auth           | Token type |
| ------------------------------------------------------ | ----------------------- | ---------- |
| `GET /healthz`                                         | none                    | —          |
| `GET /` (dashboard)                                    | admin (browser prompts) | admin      |
| `GET /api/v1/automations`                              | admin                   | admin      |
| `GET /api/v1/automations/{type}/workers[/...]`         | admin                   | admin      |
| `PATCH /api/v1/automations/{type}/workers/{id}/config` | admin                   | admin      |
| `GET /api/v1/automations/{type}/output/{length,peek}`  | admin                   | admin      |
| `POST /api/v1/automations/{type}/output/pop`           | admin                   | admin      |
| `GET /api/v1/automations/{type}/workers/{id}/config`   | worker                  | worker     |
| `WS /api/v1/automations/{type}/workers/{id}/control`   | worker                  | worker     |

Missing or malformed `Authorization` returns 401. Wrong token returns 403. Token comparison uses `secrets.compare_digest` (constant-time).

The WebSocket endpoint accepts either `Authorization: Bearer ...` header or `?token=...` query param. The header is preferred; the query param exists as a fallback for clients that can't set custom headers.

## TLS

Not built in. The master serves plain HTTP on its bind port. In production, terminate TLS at a reverse proxy:

```nginx
server {
  listen 443 ssl http2;
  server_name fleet.example.com;
  ssl_certificate ...;
  ssl_certificate_key ...;

  location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}
```

The WebSocket upgrade headers matter. Without them, worker WS connections will fail at the proxy.

Caddy works too and handles TLS automatically:

```
fleet.example.com {
  reverse_proxy localhost:8000
}
```

The master is fine being on a private network without TLS as long as the network is trusted and workers connect from within it. The dashboard prompts for the admin token via JavaScript `prompt()` which stores it in `localStorage` — fine for personal use, replace with proper SSO for any shared deployment.

## Rotating tokens

### Admin token

There's no online rotation for the admin token. Update `FLEET_ADMIN_TOKEN`, restart the master, paste the new value into the dashboard prompt (`localStorage` clears on demand from the browser console).

### Worker token (zero-downtime)

The master accepts a primary `FLEET_WORKER_TOKEN` plus an optional peer-set `FLEET_WORKER_TOKENS` for rotation overlap. The peer-set takes either a comma-separated string or a JSON list:

```bash
# step 1: add the new token to the peer set on the master
export FLEET_WORKER_TOKEN=$OLD_TOKEN
export FLEET_WORKER_TOKENS=$NEW_TOKEN
# restart the master — both tokens are now accepted
```

```bash
# step 2: roll workers across, one at a time, each gets FLEET_WORKER_TOKEN=$NEW_TOKEN
for worker in host1 host2 host3; do
  ssh "$worker" "sed -i 's/^FLEET_WORKER_TOKEN=.*/FLEET_WORKER_TOKEN=$NEW_TOKEN/' /etc/fleet.env"
  ssh "$worker" "systemctl restart fleet-worker"
done
```

```bash
# step 3: once every worker is on the new token, swap the primary and drop the peer
export FLEET_WORKER_TOKEN=$NEW_TOKEN
unset FLEET_WORKER_TOKENS
# restart the master one last time — old token stops being accepted
```

Both header (`Authorization: Bearer ...`) and query (`?token=...`) checks walk the candidate set in constant time, so the position of the matching token isn't leaked via timing. See feature 5.4.

## Compromised tokens

If you suspect a worker token leaked, rotate immediately. Tokens are the only auth — there's no IP allowlist, no mTLS, no per-worker secret.

If you suspect the admin token leaked, the surface area is larger. Anyone with the admin token can:

Read every config (including any secrets you've put in plugin-defined fields like `api_key`).

Patch any worker's config to anything that passes Pydantic validation.

Pop every output stream destructively.

After rotating, audit recent activity in worker logs and check `last_seen` / `state` for unexpected transitions. There's no built-in audit log on the master.

## Scoped tokens

For multi-tenant or external-team setups, set `FLEET_TOKEN_SCOPES` to a JSON map of `{token: [automation_types]}`. Each token then only sees its own automation types through the per-automation REST routes. The admin token implicitly has `["*"]`.

```bash
export FLEET_TOKEN_SCOPES='{
  "team-a-token-abcd...": ["cf-scraper", "cf-cookie-harvester"],
  "ops-token-9999...":    ["*"]
}'
```

Per-token submit rate-limiting is layered on top via `FLEET_SUBMIT_RPS_PER_TOKEN` (default 0 = unlimited). Over-cap requests get HTTP 429. The limiter is in-memory, so it's per-master-process; scale that with the rest of your master tier.

## Future

Per-worker tokens with explicit registration. Today the worker peer-set is shared — any worker token impersonates any worker. Per-worker credentials would let you revoke one host without touching the others.

Role-based admin auth. Splitting "read-only operator" from "config-patcher" from "stream-popper" is plausible but not yet planned.

mTLS or signed tokens. Out of scope for the framework; if you need this, terminate at a service mesh that handles it.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://fleet.hackmap.win/operations/auth.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
