Tokens & ACL¶
Every API request is authenticated with a token (except GET /api/v1/stats). A token has a unique name, a role and an optional acl. Only a SHA-256 hash of the secret is stored: the secret is shown once when the token is created or rotated.
Sending the token¶
Authorization: Bearer <token>(scheme case-insensitive)access-token: <token>header?access_token=<token>query parameter (for devices that can only fetch a URL; redacted from logs)
After CONFIG_RATE_LIMIT_FAILED_AUTH (default 20) failed attempts per client IP and minute, further attempts get 429 until the minute is over – guessing tokens doesn't scale.
Roles and default ACLs¶
| Role | Default ACL | Typical use |
|---|---|---|
admin |
* |
Administration, CLI password login |
user |
export, export/*, export/private/*, export/group/*, import, import/*, indicators, indicators/*, sources, sources/*, hits, hits/*, agent/* |
Integrations that manage sources and indicators |
guest |
export, hits, agent/* |
Public export, reporting hits, agent check-in |
A non-empty acl on the token replaces the role defaults – a machine with its own ACL that should report hits needs hits in it (since v1.33.0; the defaults got hits then too). Likewise a tis-agent that should check in needs agent/* (since v1.41.0; in the defaults since then; the token editor's Agent check-in).
ACL patterns¶
Patterns are minimatch globs matched against the request path relative to /api/v1/:
| Request | Checked against |
|---|---|
GET /api/v1/export |
export |
GET /api/v1/export/3 |
export/3 or export/<its name> or export/<its uuid> |
GET /api/v1/sources/5/fetch |
sources/5/fetch |
GET /api/v1/export/private/5,6 |
export/private/5 and export/private/6 (every source must be allowed, by ID or name) |
GET /api/v1/export/group/customer-x |
export/group/customer-x or export/group/<its id> or …/<its uuid> |
POST /api/v1/import/feed |
import/feed or import/<its id> or import/<its uuid> |
* matches one path segment (export/* matches export/3, not export/private/3); ** matches any depth.
Since v1.29.0. Sources and groups can be named in a rule by ID or name (export/google-ips, export/group/customer-x), whichever form the URL uses. Names are easier to read but can change: renaming a source or group rewrites the rules naming it exactly, so tokens keep their access (glob rules like export/google-* are not rewritten). A token without access gets 403 also for sources and groups that don't exist.
Since v1.40.0 every source and group also has a UUID, accepted wherever the ID or name is (export and import URLs, ACL rules, group source lists). It never changes and can't be guessed like an ID – the natural choice for URLs configured on customer machines. source:detail / group:detail and the details in the GUI show it. Import takes a name or UUID since then too, and import rules naming a source follow its rename like export rules.
In the GUI the permissions are edited as export (the public list, all or some sources, all or some lists), import (into all or some sources), API (indicators, sources, hit reports) and other rules; the editor writes the rules above (a selected source gets both export/<name> and export/private/<name>) and shows them.
Expiry, IP filters and sub-tokens¶
Since v1.40.0.
- Expiry –
expiresAt: a date-time, or a duration from now such as30dor52w;null= never. An expired token is refused with401 API token expired. - Client IP filters –
allowedIpsanddeniedIps: IPs and CIDRs (IPv4 and IPv6). With an allow list the token works only from those addresses; the deny list wins over it. Refused requests get403. The client address is taken fromX-Forwarded-Forof the proxies trusted byCONFIG_API_TRUST_PROXY(see Configuration). - Sub-tokens – a token created with
parentIdhas its parent's role and ACL (they follow the parent's changes and can't be set on the sub-token –400), but its own secret, expiry and IP filters. The parent's expiry and IP filters apply to it too, and deleting the parent revokes its sub-tokens. Sub-tokens have no sub-tokens of their own. Typical use: one parent per customer with the customer's permissions, one sub-token per device, each revocable on its own.
The limits apply to API requests and to signing in to the GUI and the CLI with a token's name and secret (the GUI also checks the IP filters).
Common setups¶
# customer machines pulling one group
token:create --name customer-x-pull --role guest --acl '["export/group/customer-x","hits"]'
# a firewall pulling two private sources
token:create --name fw-prague --role guest --acl '["export/private/5","export/private/google-ips"]'
# a push script importing into source 7
token:create --name honeypot-push --role guest --acl '["import/7"]'
# read-only monitoring of indicators
token:create --name monitoring --role guest --acl '["indicators","indicators/*"]'
# a customer's permissions once, a sub-token per device (v1.40.0+)
token:create --name customer-x --role guest --acl '["export/group/customer-x","hits"]'
token:create --name customer-x-fw1 --parent 12 --allow-ip 192.0.2.10 --expires 52w
# a contractor's token for 30 days from their network
token:create --name contractor --role user --expires 30d --allow-ip 198.51.100.0/24
Managing tokens¶
tokens # list (secrets are never shown)
token:update --id 5 --acl '["export"]' # "null" clears the ACL (back to role defaults)
token:update --id 5 --expires never # or a date / a duration from now (30d)
token:update --id 5 --allow-ip null # clears a filter; --deny-ip likewise
token:rotate --id 5 # new secret, shown once
token:delete --id 5
lastActiveAt (shown as Last Active) is updated at most once a minute per token – handy for finding unused tokens.
Primary admin token¶
Token ID 1 is the primary admin token. It cannot be deleted, its role cannot be changed and it cannot be given a restrictive ACL (only none, [] or one containing *). Rotate it after installation – see Installation.
Audit¶
Changes are recorded in the audit log with the token's name as actor (GUI users and CLI users with their sign-in name): audit in the CLI, Audit log in the GUI, GET /api/v1/audit.
Web CLI access¶
The browser CLI is not controlled by API ACLs: it requires an Authentik sign-in (optionally limited by CONFIG_OIDC_ALLOWED_GROUPS) or the name and secret of an admin token. See Installation – CLI sign-in.