Automation tokens
An automation token is an unattended credential for the management API: the SuperAdmin API under /api/v1/sa and the Admin API under /api/v1/adm. Scripts, orchestration tools and AI agents use it where a person would sign in with a password and a second factor.
A token is presented as a bearer credential, exactly like the session token the consoles use:
Authorization: Bearer ssat_<token id>_<secret>The string is shown exactly once, when the token is created. The server stores only a hash of the secret and cannot show it again. A lost token is revoked and a new one is minted.
Turning tokens on
Tokens are off on every installation until a SuperAdmin enables them under Global Configuration, Automation (or automationTokens in PUT /sa/globalconfig). The policy there has:
| Setting | Meaning | Default |
|---|---|---|
enabled | The global switch. Off refuses every token and forbids creating one. | off |
adminsMayCreate | Whether virtual site Admins may mint tokens bound to their own account. SuperAdmins always can. | on, once enabled |
defaultLifetimeDays | The expiry a token gets when the request names none. | 90 |
maxLifetimeDays | The longest lifetime a token may be created with. Never above 365. | 365 |
retentionDays | How long a revoked or expired token record is kept for audit before it is removed. | 90 |
serveOpenApi | Whether the server publishes its API specification at /api/v1/openapi.json. | off |
The feature needs a Professional or Ultimate license (capability automation). On a Basic license the screens are locked and every token is refused.
NOTE
The global switch is the incident response for a leaked token. Turning it off refuses every token on every node of a cluster within seconds, without touching the tokens themselves; turning it back on restores them.
What a token can do
A token belongs to the operator who created it and is checked against that operator on every request:
- Owner. The token is bound to the operator account instance. When the owner is disabled, deleted, or still owes a password change, every token of that owner is refused. A new account created later under the same name does not inherit the tokens.
- Permissions. An Admin token carries a subset of its owner's View and Edit permissions, chosen at creation. The effective permissions are always the intersection of the token's and the owner's current ones, so a token shrinks when its owner does. A SuperAdmin token has no permission lists: the plane itself is the boundary.
- Read only. The default. A read only token may call no route that writes: no POST, PUT, PATCH or DELETE, and none of the few GET routes that change state (starting or stopping a site, deactivating the license).
- Service actions. A separate scope, never implied by Edit permissions, for the routes that change the service itself: cluster membership and repair, node drain, software updates, starting and stopping virtual sites, renewing a certificate now, activating or deactivating the license, and terminating sessions.
- Address allow list. Optional list of addresses and networks (CIDR) the token may be used from.
- Expiry. Mandatory, within the policy cap. A notification warns the owner seven days before.
- Disabled flag. A token can be paused and resumed by its owner without revoking it.
Some routes are never available to a token, whatever its scopes: everything about operator credentials (passwords, second factors, recovery codes, trusted devices, passkeys), operator accounts (SuperAdmins and Admins), the operator sign in providers, the backup and restore of the whole configuration, and the token routes themselves. A token can never create a token. The one exception is GET .../automation-tokens/self, which tells a token what it may do.
Managing tokens
| Operation | SuperAdmin | Admin |
|---|---|---|
List own tokens (?all=true lists every SuperAdmin token) | GET /sa/automation-tokens | GET /adm/automation-tokens |
| Create | POST /sa/automation-tokens | POST /adm/automation-tokens |
| Read one | GET /sa/automation-tokens/{id} | GET /adm/automation-tokens/{id} |
| Change name, description, disabled flag, allow list | PATCH /sa/automation-tokens/{id} | PATCH /adm/automation-tokens/{id} |
| Revoke | DELETE /sa/automation-tokens/{id} | DELETE /adm/automation-tokens/{id} |
| What the calling token may do | GET /sa/automation-tokens/self | GET /adm/automation-tokens/self |
| Oversight of a site's Admin tokens | GET /sa/vsites/{id}/automation-tokens, DELETE /sa/vsites/{id}/automation-tokens/{tokenID} |
The consoles offer the same under Automation, Automation tokens (Admin) and Automation tokens (SuperAdmin). A create request names the token, optionally its description, expiry (ISO 8601), permissions, readOnly, serviceActions and allowList. The answer is 201 with the token record and, once, the secret. Scopes and expiry are fixed after creation: a token that needs more is a new token.
Revoking marks the record revoked and refuses the token on every node within seconds. The record stays visible, revoked, until the retention period ends, so the audit trail keeps the owner and the scopes.
Audit
Every change made with a token is recorded in the operator audit trail with two extra fields: actorKind is token, and actorToken is the token ID. The actor and actorRole fields name the owner, exactly as they would for the owner at a console. The events that concern tokens themselves:
| ID | Event |
|---|---|
| 6130 | A token was presented and refused (the reason field says why). Throttled per token and source address. |
| 6131 | A valid token called a route outside its scope (reason is routeForbidden, readOnly or serviceActions). |
| 6211 | A token was issued. |
| 6212 | A token was revoked. |
| 6213 | A token expires within seven days. |
| 7091 | A dry run was performed; nothing was persisted. |
Refusals
A refused token answers 401 with a WWW-Authenticate: Bearer challenge and one of these codes in messageCode (see Reason codes):
| Code | Why |
|---|---|
webrest.auth.automationTokensDisabled | The global switch is off. |
webrest.auth.automationNotLicensed | The license does not include automation. |
webrest.auth.automationTokenRejected | Unknown token, wrong secret, paused token, or a token of the other plane. The log says which. |
webrest.auth.automationTokenExpired | Past its expiry. |
webrest.auth.automationTokenRevoked | Revoked. |
webrest.auth.automationTokenOwnerDisabled | The owner cannot sign in. |
webrest.auth.sourceNotAllowed (403) | The source address is not in the token's allow list. |
webrest.token.routeForbidden (403) | A route tokens never reach. |
webrest.token.readOnly (403) | A write with a read only token. |
webrest.token.serviceActionsRequired (403) | A service action without the scope. |
Good practice
- Mint one token per integration, named after it, with the narrowest permissions that work and an address allow list where the caller's addresses are known.
- Prefer read only tokens; give write permissions to the one token that needs them.
- Store the secret in the caller's secret manager or an environment variable, never in a URL or a command line.
- Rotate before expiry: create the new token, switch the caller, revoke the old one.
- Watch events 6130 and 6131: a healthy integration produces none.
