Appearance
API Tokens & Scopes
A Personal Access Token (PAT) lets a script, a CI job, or an AI agent call the SeyalRun API as you — but confined to a set of scopes you choose when you issue it.
Issuing a token
Admin → Security → Personal Access Tokens → + Token
- Give it a name that says who will use it (
ci-deploy,ops-copilot) — this is what appears in the audit log alongside your username. - Pick the scopes. The picker is populated live from the server's catalog (
GET /api/v1/api-tokens/scopes), split into Read and Actions. A token with no scopes can do nothing, so Create stays disabled until you select at least one. - Optionally set an expiry.
- Copy the
sr_…value. It is shown once — SeyalRun stores only a hash.
Tokens are listed with their prefix, scopes, last-used time, and expiry; you can revoke one at any time, which takes effect on the next request.
Using a token
sh
curl -k https://your-seyalrun-host:8443/api/v1/hosts \
-H "Authorization: Bearer sr_your_token_here"The same header authenticates the MCP server.
The scope catalog
Scopes are domain:action. Reads are the baseline; actions are opt-in.
Read scopes
| Scope | Grants |
|---|---|
inventory:read | Hosts, host groups, zones, credential templates |
automation:read | Projects, job templates, schedules, job runs |
sessions:read | Session history and recordings |
audit:read | The audit log |
metrics:read | The metrics dashboard |
notifications:read | Notifications |
Action scopes
| Scope | Grants |
|---|---|
automation:run | Run an allowlisted job template (POST /job-templates/{id}/run) |
inventory:write | Create/edit hosts, host groups, zones |
sessions:open | Open SSH/SFTP sessions |
notifications:ack | Acknowledge notifications |
automation:run is deliberately separate from automation:write. Running an approved playbook and editing what that playbook does are different levels of trust — an agent that can run templates cannot rewrite them.
Never grantable
credentials:read, credentials:write, and every admin:* scope are rejected at issuance with a 400, and would be unsatisfiable at the gateway even if a token somehow carried them. See the two hard lines.
How enforcement works
On every request, api-gateway checks — in order — the caller's session/token validity, then their role (RBAC), then, only for PAT callers, their scopes:
role says no → 403 forbidden: your role does not permit this action
scope says no → 403 forbidden: token scope does not permit this actionA browser session carries no scopes and is governed by role alone; a PAT is governed by role and scopes. That ordering is why a token can only ever do less than its owner, never more.
Two properties worth knowing:
- Deny by default. The scope required for a route comes from an explicit segment→scope map. A route that isn't in the map is closed to tokens until someone classifies it — new endpoints are not silently reachable.
- An empty scope list denies everything. There is no "no scopes means unrestricted" fallback.
Legacy read / write tokens
Tokens issued before fine-grained scopes carry the coarse read or write scope. Those still work — read satisfies any read, write any write — so existing integrations did not break. They are, however, far blunter than the per-domain scopes. Reissue them when convenient.
How tokens are stored
The raw token is never persisted. SeyalRun stores an Argon2 hash of token + API_TOKEN_PEPPER, where the pepper lives only in .env — so a full database dump still doesn't let an attacker forge or crack a token. Only the first few characters (the sr_ prefix plus six) are kept in clear, to identify a token in the UI.
Practical advice
- One token per consumer, not one shared token. Revoking a leaked CI token shouldn't take down your agent.
- Grant reads first. Let an agent observe before you give it an action scope.
sessions:openis the heavy one. It lets the holder open an interactive session — the same thing a human operator does, with the same recording and command filtering, but without a human at the keyboard. Preferautomation:runfor agents.
