Skip to content

Role-based access control

Anvil has three roles: viewer, operator, admin. They form a hierarchy: admin > operator > viewer. Every admin is also an operator; every operator is also a viewer.

What each role can do

Action viewer operator admin
View dashboard, devices, runs
View Run Detail + download export
See public-share is_shared flag
See public-share active slug
Start a run
Abort a run
Create / revoke share links
Save / share comparisons
Administer users (CRUD)
Configure SSO
One-click env auto-tune

Credentials

  • Password: bcrypt hashed, stored in users.password_hash. Anvil enforces bcrypt's 72-byte password cap by truncating at 72 bytes on encode (pre-hash), which matches passlib's legacy behavior.
  • JWT: HS256, signed with ANVIL_BEARER_TOKEN, 12-hour expiry. Claims: sub=user_id, username, role, exp.
  • Legacy bearer token (ANVIL_BEARER_TOKEN): still a valid admin credential; used by automation and the bootstrap admin flow.

Bootstrap admin

On first boot (and on a DB where no active admin exists yet), Anvil creates or promotes a user admin with password = first 16 chars of ANVIL_BEARER_TOKEN. Rotate this password immediately.

If an admin user already exists (possibly disabled from a prior deployment), Anvil promotes that row instead of creating a duplicate.

Why role changes force re-login

A JWT embeds the user's role at issuance time. If an admin changes a user's role while their JWT is still valid, the next authenticated request fails with 403 Role changed; sign in again. This prevents a just-demoted user from continuing to act as an operator until their token expires.