Skip to content

Roles & access control

Pier’s authorization model has two scopes. Every user carries one global role, and a user can additionally hold a project role on each project they’re a member of. Most endpoints check one or the other; a few high-impact ones are reserved for the Owner.

A global role is stored on the user record and travels with every authenticated request. There are three, ordered from most to least privileged.

RoleWhat it can do
OwnerEverything Admin can, plus the Owner-only knobs: changing other users’ global roles, deleting/promoting Admins, federation grants, and the WireGuard mesh. The first user created at setup is the Owner. At least one active Owner is always required.
AdminManage users (invite, edit, remove non-Owners), manage servers, view system metrics and the audit log, create projects, and operate Docker-level resources (containers, images, compose stacks, networks, registries). Bypasses project membership — an Admin reaches every project.
UserA regular member. Sees only the projects they’re an explicit member of, plus read-only global endpoints (server list, system metrics). Cannot create projects or manage users.

Global Owner and Admin both bypass project-membership checks — they’re treated as project Admin on every project.

A project role is granted via project membership (the project_members table) and scopes a User’s reach to a single project without giving them global power. There are three.

RoleWhat it can do within the project
AdminEverything Editor can, plus manage the project’s membership (add/remove members, change their roles).
EditorDeploy and redeploy services, change env vars, domains and settings, restart.
ViewerRead-only: configs, logs, metrics, and deployment history.

Each project keeps at least one project Admin: Pier refuses to demote or remove the last one.

Two mechanisms enforce roles:

  • Router-level global guards. Whole groups of routes sit behind a middleware layer. require_global_admin gates user management, Docker daemon ops, compose stacks, registries, the audit log, and server mutations. require_global_owner gates global-role changes (PUT /users/{id}/role), the mesh, and federation grants.
  • In-handler project checks. Project-scoped routes (resources, deployments, env, backups) call enforce_project_role / enforce_resource_role at the top of the handler, resolving the resource to its project and requiring a minimum project role.

A concise map of common actions:

ActionMinimum role
Browse the catalog / view a project’s servicesViewer (project)
Deploy or redeploy a service, edit env/domainsEditor (project)
Add or remove a project memberAdmin (project)
Create a new projectAdmin (global)
Invite or remove users, view audit logAdmin (global)
Promote a user to Admin, or change any global roleOwner (global)
Manage federation grants or the WireGuard meshOwner (global)