Console session and revocations
A local account whose authorities name an admin role signs in to the admin
console with a username and password; the server gives it back a session
token that it signs itself.
[auth.methods]
local = { enabled = true, password = true }
[[users]]
username = "eric"
password_hash = "$argon2id$..."
authorities = ["admins"]
[[admin.roles]]
name = "admins"
permissions = ["overview", "sessions", "kick", "bans", "unban", "config", "logs", "audit", "revoke", "grant"]
[admin.ban]
max_failures = 5
[admin.session]
key_file = "/secrets/admin-session.key" # at least 32 bytes, the same on every instance
ttl_secs = 3600
max_age_secs = 43200
Sign-in counts its failures in [admin.ban], which it requires
(Bans), and goes through the
password hashing queue (Password hashing).
Signing in
| Request | Response |
|---|---|
POST /admin/login {"username": "...", "password": "..."} | token, to send as Bearer; username, expires_at, expires_in, auth_time, roles, permissions |
GET /admin/login | {"password": true} when the door signs in accounts |
POST /admin/session/renew (session token) | a new token, as long as max_age_secs since sign-in has not passed |
GET /admin/me (any token) | name, method, permissions, admin roles, expires_at, expires_in, auth_time |
The token carries only the account: each request re-reads the account in
effect ([[users]] or users_file) and recomputes its permissions. A reload
of users_file that removes a role, changes the password or removes the
account applies to the next request.
The session key
The key that signs tokens is the same on every instance: key_file, or under
Kubernetes secret_name
(Secrets). Without either,
the key is drawn at startup: sessions live with the process, on this instance
only. All the keys:
Reference [admin.session].
Revoking, signing out
| Request | Effect |
|---|---|
POST /admin/revocations {"username": "eric"} (permission revoke) | every session token of the account issued until then is refused, on all its tabs and devices; a new sign-in goes through. The response says lift: held (the shared state holds the revocation) or local_only (this instance only) |
POST /admin/logout | the same for the caller’s account; under a provider JWT or the static token, nothing is revoked (204) and the console forgets the token |
GET /admin/revocations | the revocations in effect; each one disappears max_age_secs after its issued_before |
Streams opened under a revoked token (/admin/events, log follows) are
closed.
Sharing revocations
[admin.session]
persist_file = "/var/lib/craft-file-gate/admin-revocations.json" # a file of their own
# or, on Kubernetes:
# backend = "configmap" # the chart sets it with the shared Secret
# revocation_configmap_name = "craft-file-gate-access"
reread_interval_secs = 5
All the keys: Reference [admin.session].
A shared key goes with shared revocations, and with synchronized clocks (NTP): a revocation is dated, and an instance whose clock runs ahead or behind applies it with that offset.
In the console
- Username and password when the door signs in accounts; “Sign in with a token” takes the static token or a provider JWT, and is the only form otherwise.
- The token lives in the page: reloading, opening a tab or closing the browser asks for sign-in again. The browser keeps only the theme and the table views.
- The session is renewed as long as the page is open, up to
max_age_secsafter sign-in; a closed tab lets it end atttl_secs. The header shows the account, its admin roles and the token’s end. - Logout calls
POST /admin/logout: one session signs out every tab and device of the account.