Skip to content

Permissions and scopes

Opfield uses explicit scopes. A scope has a capability base and may include a resource suffix.

docker:containers:view
docker:containers:view:<node-id>/<resource-id>
databases:view:<database-id>
nodes:details:<node-id>

The capability base describes the permitted action. A resource suffix narrows that action to a Node or resource identity. Opfield evaluates the authenticated identity, effective group and direct grants, resource ownership, current product state, and plan entitlement at the backend operation boundary. Navigation visibility and disabled controls help users understand access, but they are not authorization.

Permissions answer two separate questions: which action is allowed, and which resource is in scope. A user may be able to view a Container without seeing sensitive host details, or manage one Route without managing every Route on its Ingress Node. Prefer the smallest grant that supports the real workflow rather than giving broad access to avoid a missing screen.

  1. Grant through groups for normal access; reserve direct user additions for exceptions.
  2. Prefer resource-scoped grants over an entire node or product area.
  3. Separate viewing from mutation, secret reveal, export, mounts, and destructive actions.
  4. Treat API tokens and OAuth grants as delegated authority, not as alternate administrators.
  5. Test the resulting user journey, including navigation visibility and direct API denial.

Start with the job the identity must perform. List the read actions needed to discover and verify the target, the mutation actions needed to change it, and any separately protected data or destructive action. Then limit each grant to the exact resource, Node, or folder where the work belongs. Group membership is normally easier to review and revoke than many direct user grants.

Do not grant a global management scope merely because the workflow crosses several resource types. A publication workflow may need limited access to a Pages Project, Domain, certificate, Route, and Build Worker status while still not needing general Node administration or private-key export. Test the complete workflow with the intended non-admin identity before production use.

Global scopes apply across the permitted product area. Node-scoped grants restrict operations to resources on a specific managed Node when the resource contract supports that scope. Resource-scoped grants identify one durable Opfield resource. Folders can group supported resources and participate in access design, but moving a resource into a folder does not change its runtime ownership or network path.

Any action scope implies view of the same resources: proxy:edit:<route-id> shows that Route, and docker:containers:manage:<node-id> shows the containers on that Node. Creation scopes are the exception: they imply no view at all, whether they are broad or restricted to a folder or Node. See Implied view access.

Resource visibility and host visibility are intentionally distinct. A user can operate an assigned workload without learning unrelated host inventory. Search, navigation, REST, MCP discovery, realtime subscriptions, and direct resource requests must all apply the same effective access rules. A hidden navigation item is not proof of denial; verify a direct request as well.

A folder grant limits a user, group, API token, or OAuth grant to the resources inside one folder and its subfolders. It suits a project team that should see and operate only its own resources, for example everything that belongs to MyProject.

  1. Create a MyProject folder in each area the team uses, for example Routes, Docker containers, and Databases. Each resource type has its own folder tree, so a Routes folder does not cover containers. See Folder support by resource type.
  2. Move the project’s existing resources into those folders. Moving a resource needs the area’s folder-management scope and edit access to the resource.
  3. In the group editor or the user’s additional permissions, select the scopes the team needs, open each scope’s restriction, and choose the MyProject folder. The saved grant has the form <scope>:folder/<folder-id>.
Goal Scopes restricted to the folder
See and operate the project’s containers and Deployments docker:containers:view, docker:containers:manage; add docker:containers:environment, docker:containers:secrets, or docker:containers:console only when needed
Create new containers and Deployments in the folder, including pulling their images docker:containers:create
Manage the project’s Routes proxy:view, proxy:edit, proxy:create
Query the project’s databases databases:view, databases:query:read

What the user sees:

  • Every resource in the folder and its subfolders, including resources created in or moved into it later. Opfield resolves folder grants on every request, and open pages pick up newly visible resources without signing in again.
  • Nothing else: lists show only the granted resources, a granted folder that is still empty shows an empty list, and direct requests for other resources are denied. A resource moved out of the folder stops being visible unless the user has a separate grant for it.
  • Create dialogs offer only the folders the user may create in. No folder is hidden when the user cannot create at the top level, and the only allowed folder is preselected. Through the API or MCP, pass the folder as folderId; creating elsewhere returns 403. Where a resource runs on a Node, the dialog lists only Nodes the user may deploy to, without granting Node administration.
  • A creation scope alone shows the folder as a destination but none of its contents. Grant a view scope on the folder as well when the team should see what is already there.
  • Containers and Deployments created from a Git source go into the chosen folder, also when the first build creates them later. While one waits for its first build it is listed in that folder and can be moved with Move to folder… or by dragging; the first build then creates it in the folder it is in at that moment. See Folder placement of built workloads.
  • A refused create names the folders and Nodes where the user may create instead, for example Missing docker:containers:create at the root (no folder). Your docker:containers:create access is limited to folder 'MyProject' (<id>): pass folderId for one of them. Docker creates return this message in the Console and the REST API; for other resource types, MCP and AI Workspace tool errors add the same list of folders and Nodes.

Settings > Authentication > Identity provisioning > Auto-assign permissions for created resources is on by default. It adds grants for each new resource to its creator’s additional permissions: view of the new resource always, and other per-resource scopes only when the creator already holds them broadly or on the destination folder or Node. A user with only a creation scope therefore sees exactly the resources they created. A folder-limited creator therefore keeps the same access if the resource is later moved out of the folder, but gains nothing new: view and create on a folder do not turn into console or secret access. Turning the setting off affects new resources only; existing grants stay and can be changed in Assign permissions.

API tokens and OAuth grants accept the same folder restrictions. Their folders are resolved first and the result is then limited by the owner’s own access, so a token never sees more than its owner; see Restrict tokens and OAuth grants.

GET /api/auth/me/access returns the caller’s access grouped by product area: whether it is broad or limited, the granted folders with their paths, the Nodes, accounts, and individual resources with the actions allowed on each, and where the caller may create (create.atRoot, create.folders, create.nodes). It works with a session, an API token, or an OAuth token, and reports a token or OAuth grant as bounded by its owner’s current access. The user’s ID, name, email, and group are included only for a browser session and the AI Workspace, never for a token. MCP clients and the AI Workspace get the same summary from the get_my_access tool, and MCP also serves it as the gateway://access resource; see Find out what the caller can access.

Folder-limited access is normal for agents and automation. A list returns only what the caller may see, so an empty list at the root is not a denial. When you test a folder-limited identity, read its access summary first, then create in one of the listed folders with folderId.

Git integration scopes can be limited to one connected account and, below it, to GitLab groups and projects or GitHub owners and repositories. A grant on a GitLab group covers its subgroups and every project under them; a grant on a GitHub owner covers every repository of that organization or user. In the group editor, a user’s additional permissions, the API token form, and OAuth and MCP consent, check a connector to cover all of its repositories, or open Add groups or projects… (GitLab) or Add owners or repositories… (GitHub) under the connector and search for narrower targets. Grants store stable provider IDs, so renaming or moving a group or repository does not change them.

To let a team build from one project, grant integrations:gitlab:use on that project next to the workload’s own permissions: use on the project is enough to configure a Docker or Pages build source. Keep that grant in place: manual builds check it again, and automatic builds of a source saved in this release pause when the account that saved it loses use. API tokens and OAuth grants carry the same restrictions and never reach a repository that their owner cannot reach at that moment. See Git integration restrictions for the qualifier format and Restrict repository access for what each operation checks.

Resource-scoped Docker permissions work on containers that Opfield discovered but did not create. You can let a team restart a service and read its logs without handing the whole host, or the application’s configuration, over to Opfield.

Goal Grant Notes
Read logs, statistics, and processes of one standalone container docker:containers:view:<node-id>/<resource-id> There is no separate logs scope; view covers them
Start, stop, restart, or kill one standalone container and read its logs docker:containers:manage:<node-id>/<resource-id> manage implies view on the same container. It also allows kill and recreate; there is no restart-only scope
Open a shell in that container add docker:containers:console:<node-id>/<resource-id> Console access is always a separate grant
Read the aggregated logs and monitoring of an external Compose project docker:compose:view:<node-id>/<project-id> Works before adoption and on every plan
Start, stop, or restart a Compose project docker:compose:manage:<node-id>/<project-id> after the project is adopted External projects are read-only until adoption; lifecycle actions apply to the whole project, not to individual Compose containers
Apply the same access to a group of resources the same scopes with folder/<folder-id> Covers supported resources in the Docker folder and its subfolders

A standalone container is any container without Docker Compose project labels, including one started with docker run. Opfield gives it a stable resource identity that survives recreate and update operations performed through Opfield. If the container is removed and started again outside Opfield, Opfield records a new resource and revokes grants on the old identity. See Containers that Opfield did not create.

An external Compose project keeps its identity while Opfield observes it. If the project disappears from the Node, for example after docker compose down, Opfield removes it from inventory unless the project is placed in a Docker folder; when it reappears it receives a new identity, and grants on the old project identity no longer match. Place external projects that carry project-scoped grants in a Docker folder, or grant access through the folder.

  • Container editing does not imply mount editing.
  • Database access does not imply credential reveal.
  • Inference use does not imply AI Workspace access.
  • Viewing a resource does not imply viewing its host node details.
  • Route editing does not imply certificate private-key export.

Other sensitive operations follow the same principle. Console or file access is separate from ordinary workload viewing. Archive export is separate from viewing files or resource configuration. Secret mutation does not imply secret reveal, and write-only values are replaced rather than retrieved. OAuth consent and MCP tool discovery do not add scopes that the owning user does not have.

AI Workspace and remote MCP remain within normal Opfield authorization. AI Workspace access and Opfield Inference use are separate capabilities. Remote MCP requires its own OAuth resource and mcp:use; browser sessions, ordinary gw_ API tokens, logging tokens, inference tokens, or OAuth tokens issued for another resource are not interchangeable MCP credentials.

Use separate credentials for interactive administration, CI, monitoring, and third-party tools. An API token acts with delegated authority from its Opfield user. An OAuth client adds an explicit redirect and consent lifecycle. Remote MCP uses OAuth and exposes only tools compatible with the current identity and product state. A dedicated gwi_ token belongs to the Opfield Inference data plane and cannot be used as a normal Opfield API credential.

Create automation credentials with an owner, purpose, expected rotation, and known dependent system. Store secrets once in a secret manager, never in repository URLs, command history, screenshots, or logs. Test one permitted action and one denied action. If a token is lost, create a replacement and revoke the old value; masked secrets cannot be recovered from the UI.

Session, API, MCP, and protected WebSocket operations revalidate access. Revoking a group, token, or resource grant must stop new privileged actions and terminate protected streams where required. A previously loaded page or discovered tool does not preserve authority after revocation.

When a user’s responsibilities change, review group membership, direct grants, active sessions, API tokens, OAuth grants, and automation dependencies together. Blocking a user stops new use without erasing attribution. Deleting a user preserves historical audit records, and restoring a deleted record does not silently reactivate it. Removing the last administrator is refused.

Deleting a resource—a Node, Route, Domain, certificate, CA, Access List, template, group, folder, connector, Pages Project, database, storage, logging environment, Deployment, Compose Project, or another resource—removes every permission that names it from users, groups, API tokens, and OAuth and MCP grants, so a later resource with the same name never inherits them. Permissions left on resources deleted before 2.11 are removed at startup and every hour.

For credential rotation, create the replacement, update the dependent system, verify successful use, then revoke the old credential. After suspected disclosure, revoke first when operationally safe, inspect audit activity and request IDs, invalidate related sessions separately, and rotate any downstream secret that may have been exposed.

Test permissions from the identity that will use them, not from an administrator account. Confirm the expected navigation and search visibility, read the target resource, perform one allowed operation, and attempt one clearly out-of-scope operation. For automation, also test validation failure and asynchronous Task follow-up.

Interpret common failures precisely: 401 indicates missing or invalid authentication; 403 usually means a missing scope or entitlement; 404 can reflect resource visibility as well as absence; 409 indicates a lifecycle, quota, or current-state conflict; and 422 indicates invalid input. Do not solve an entitlement or lifecycle conflict by widening permissions.

See Scopes, tokens, and OAuth for implementation workflows.