Skip to content

Tokens & API keys

Three token classes, three storage forms.

User JWT

Standard login token after successful login + 2FA.

Field Value
Format RS256 signed JWT
Claims sub (user ID), tenant_id, tenant_scope, permissions[], exp
Lifetime default 24 h, refreshable
Secret SECRET_KEY (RSA private key, default HMAC symmetric)
Storage browser (HttpOnly cookie + localStorage), mobile app AsyncStorage

Refresh

Before expiry a new token is fetched automatically — as long as the refresh token is valid (default 7 days). Refresh token is invalidated on logout.

Invalidation

There's no server-side JWT blocklist (too costly). On logout: frontend discards the token. On account block: users.active = false causes resource lookups for the user to fail in future requests — token effectively expires next request.

JWT in browser is as secure as the browser

XSS protection is mandatory: strict CSP header, no user content as HTML without escape, wiki Markdown is sanitized. All on the frontend.

Agent token

For agents on monitored machines.

Field Value
Format vesana_agent_<32 url-safe base64>
Server storage SHA256 hash in agent_tokens.token_hash
Agent storage plaintext in /etc/vesana-agent/config.yaml (chmod 600)
Lifetime unlimited
Binding 1:1 to a host
Auth header X-Agent-Token: vesana_agent_xxxx

Generation

UI only on the host detail. Plaintext shown exactly once. Backend stores only the hash.

Rotation

Host detail → Revoke token → new token. On the machine the config must be updated, otherwise the agent gets 401.

Or: re-install via one-command installer with new token.

Collector API key

For collectors in the customer network.

Field Value
Format vesana_<custom-prefix>_<32 bytes>
Server storage SHA256 hash in api_keys.key_hash
Collector storage plaintext in /etc/vesana/collector.env
Auth header X-API-Key: vesana_xxxxx
Binding 1:1 to a collector

key_prefix hasn't been written for new keys since v0.x (empty string). Receiver lookup is via key_hash only.

Personal access tokens

Through /profile → API keys, users can also generate personal API keys — for CLI scripts, integrations.

Field Value
Scope read-only / read-write
Expiry required (max 1 year)
Tenant scope as the user

Use: Authorization: Bearer <pat>.

Rotation: revoke old → create new. Recommendation: rotate at least yearly.

Hashing

All tokens are SHA256 hashed in DB. Benefit:

  • DB leak doesn't reveal a working token
  • Comparison with hashed values is O(1) on index

We don't salt — tokens are random enough (32 bytes entropy >> brute-forceable).

TLS required

Tokens are accepted only via HTTPS. HTTP requests get redirect (frontend) or 426 Upgrade Required (API). Self-signed certs are OK for tests, in production: Let's Encrypt or own cert.

Audit

Token operations (create / revoke) appear in audit log with action = agent_token.create / .revoke / api_key.create / .revoke.

Theft detection

Symptom Possible cause
Agent token reporting from two IPs token compromised or cloned
API key suddenly used for unusual endpoints PAT possibly pushed to repo
User JWT active on two devices normal — no problem

For agent and collector tokens: multi-IP heuristic in the UI (column „Last IP") helps spot anomalies.

Next