Skip to main content

Roles & Permissions

This page is the single source of truth for what each organization role can do. Organizations & Teams explains how roles are assigned; the MCP Reference documents each tool. This page answers one question: what can a Member do?

Two checks, not one

Every call against your infrastructure passes two independent checks, and both must pass:

  1. Tenancy — are you in the organization that owns this network, node, or service? Objects belonging to organizations you are not in are reported as not found, never as forbidden, so membership itself is not something an outsider can probe.
  2. Role — does your role in that organization permit this action?

They are separate on purpose, and the distinction explains the shape of the table below. Passing the tenancy check makes you a Member; it does not make you an Admin. It is also why Member is not a read-only role — a Member operates the fleet fully. What the higher roles add is authority over the organization itself, and over the handful of actions that change who else can reach something.

Capability matrix

You can…OwnerAdminMember
View networks, nodes, services, and the member list
Audit log — read the organization's tool-call history
Networks — create, delete
Nodes — register, provision, stop, deprovision, change a machine's deadline 1
Rename a nodenode_rename 4
Node labelsnode_label set / remove
Node grantsnode_grant, node_revoke
Node settingsnode_config_get, node_config_set 3
Commands & files on a nodecommand, file, fs_*, the event bus
Node diagnosticsnet_*, node_logs
Elevated executionadmin: true on any of the above
A node's own storage area — read or write it 2
Services — publish, update, delete, share, check
Service authentication — turning auth_required off
Org membership — invite, remove, change roles, rename the org
Billing — checkout, billing portal, spend cap, the plan/card/invoice read, usage credit
SSO — connect an identity provider, enforce SSO login
Org lifecycle — transfer ownership, delete the organization

An Admin cannot manage Owners or grant the Owner role. An organization always retains at least one Owner.

1 Provisioning needs no account-level capability, from router 0.4.110 — every account may provision, on every plan, and your organization role is the only thing that decides it. Before that release provision_node and deprovision_node also required provisioning to be enabled per account, granted by email domain. What remains is a revocation lever, used only to stop an abusive account: an account it has been applied to is refused provision_node — and, from router 0.4.125, task_deadline_set, which makes a machine run longer and so counts as starting compute — whatever role it holds, while the two calls that stop compute, deprovision_node and — from router 0.4.149task_stop, keep working for it, so nothing is left running with no way to stop it. What ordinarily refuses a provision is the plan's compute allowance or an empty credit balance, which is resource_exhausted and not a permission refusal.

2 Each node has a storage area of its own, separate from every network's share, at https://files.nobgp.com/nodes/<node-id>/ (router 0.4.54+) and — from router 0.4.56 — from the file tools, by sending storage: true alongside the node's id. It sits above those tools' ordinary tier rather than beside it: fs_write on a node's own disk reaches it through its agent, which applies its owner's allow-roots and allow-tools vetoes first, while a write to this area lands in storage with no agent and no veto in front of it — and the node may later read whatever is put there. Whichever way the request arrives, a Member is refused with a 403 naming the requirement; someone outside the owning organization gets a 404, since the node's existence is not theirs to learn. A node itself always reaches its own area, at either granted tier — and from router 0.4.73 another node's only with the manage tier, and only for peers inside its own network and its grant's targets, everything else being a 404. Before 0.4.73 that one path asked what the node's owner held in the organization, so a node on the read-only observe tier could read and write the area of any node in any network its owner's organization held.

3 node_config_get / node_config_set (router 0.4.85+, answered by agents 0.4.87+) read and merge a node's own agent settings. The read sits at the same tier as the write, deliberately: splitting the two halves of one read-modify-write would give a caller who may change a setting no way to see it first. They are Owner/Admin rather than Member because these are a node's operating configuration rather than the fleet metadata a Member reads — and because the file they write is the one holding the node's own vetoes. The node itself refuses those keys, and the tier is what keeps that refusal from being the only thing standing between a Member and a node's behaviour.

4 Renaming a node is an Owner/Admin act, from router 0.4.112 — the same tier renaming a network has always required, and a narrowing: any member of the organization could rename any node in it, including one another member provisioned. Only the rename moves; everything else a Member does with a node is untouched, deliberately, including registering, provisioning and deprovisioning it, picking its release channel and removing it. It can be done in the web app or, from router 0.4.120, with node_rename; both enforce the same tier, and a refused rename comes back as a 403 rather than silently doing nothing. What a rename does and does not move is Node identity; on a provisioned node, also read Renaming a provisioned node.

A network's shared drive carries no such step up: reading and writing it is Member-level, the same access the network already implies, whether you use the drive mounted on your nodes, its URL, or the file tools with a network named and no node.

Two of these are field-level, not tool-level

Two rows in that table gate a field inside a tool that any Member may call. This is the distinction most easily read wrong, so it is worth stating plainly.

admin: true — elevated execution

A Member may call command, file, the fs_* tools and service_publish. They may not send admin: true on any of them. The call runs as the account the node's owner configured; asking for the node's ambient identity — root on Unix, LocalSystem on Windows — needs Owner or Admin. On command, file and the fs_* tools a Member also gets forbidden when admin is omitted on a node that offers only its ambient identity, because that call would run elevated.

The gate is on the identity the operation will run as, not on whether the request spelled the field: updating a terminal service that is already stored admin: true needs the same authority even when you omit admin, because the stored identity carries over to whatever command you put in it. Lowering to the configured account never needs authority.

What "the account the node's owner configured" means, and what happens when there is none, is Execution identity below. The per-tool contract is in the MCP Reference.

auth_required: false — turning service authentication off

A Member may publish, update, delete and share services. They may not use service_update to set auth_required: false, or service_publish to create a service that way.

Publishing is an operational act, and everything a Member publishes is reachable only by someone who can authenticate. Clearing auth_required is the one edit that changes who can reach it — from someone with an account to anyone with the URL — which makes it a decision about the organization's exposure rather than about the service.

The gate is on the transition, and it is narrower than the admin one:

Needs Owner/Admin
service_update moving auth_required from true to falseyes
service_publish creating a service with auth_required: falseyes
Turning authentication back onno
Omitting auth_required — it means "leave as is", never falseno
Editing the title, target, or any other field of a service that is already unauthenticatedno

That last row is deliberate. A service that was already public is public before your change and public after it, so an ordinary edit to it is an ordinary edit. Passing authorized_emails forces authentication back on, so it is never gated.

Execution identity

Roles decide who may ask. Execution identity decides what the work runs as once the asking is allowed. Two different questions, answered by two different people — your organization decides the first, the node's owner decides the second — and neither substitutes for the other. An Owner cannot be root on a node that refuses root, and a role no more grants an identity than an identity grants a role.

Four rules cover it. They hold everywhere the admin field appears: command, command_subscribe, file and the fs_* tools, fs_grep_subscribe (router 0.4.81+), service_publish and service_update, and the browser terminal behind a published service. Rule 1 does not apply to service_publish and service_update: an omitted admin is false on service_publish and keeps the stored identity on service_update.

On the two fan-out tools — command_subscribe and fs_grep_subscribeadmin: "true" checks your authority to elevate once, on the network's organization, so that cohort is never partly elevated. With admin omitted, a caller who may not elevate gets a refused event on each node that would run elevated, and the rest of the cohort runs unelevated. Each node's own veto is reported as that node's event while the rest of the cohort carries on.

  1. Omit admin, and the node picks the identity it offers.
  2. The node decides what unelevated work runs as — not the caller, not us.
  3. A node can refuse admin entirely.
  4. A node that refuses admin must name an account, or it cannot run anything.

Omit admin, and the node picks the identity it offers

admin has three states on the tools that run something:

  • admin omitted (the default). The call runs unelevated when the node offers an unelevated identity. It runs elevated when the node offers only its ambient identity. The result reports admin_used, a boolean. true means that the call ran elevated.
  • admin: "true". The call runs elevated. It fails where elevation is not allowed.
  • admin: "false". The call runs unelevated. It fails where the node has no unelevated identity.

An omitted admin can run elevated. Send admin: "false" when the work must not run as the superuser.

What the field looks like on the wire

From router 0.4.83 admin is a string on the tools that run something. The values are "true" and "false". A JSON boolean is still accepted and coerced, so nothing a client already sends breaks. Any other string is refused with invalid_args, and the message names the two. On service_publish and service_update it stays a plain boolean. See admin is a string.

admin: "false" only means something if there is a lesser account to be. Where there is not — a root service install with no account configured, an account that was deleted or came off another machine, or user: root spelled out — an admin: "false" request is refused rather than quietly run as root, with failed_precondition (HTTP 403, not retryable). On the same node an omitted admin runs elevated, and it needs the authority to elevate. The refusal names both remedies, and the full treatment is Unelevated never means root.

The one case that is not refused is a node whose agent is already unprivileged — a rootless container, a user-level install — with no account configured. There admin: true would resolve to the very same identity, so there is no elevation to prevent, and the node serves unelevated work as itself. ⚠ The router resolves an omitted admin there as elevated, because the node reports no account. So that call needs the authority to elevate and reports admin_used: true, although it runs as the same uid. A caller without that authority sends admin: "false".

The node decides what unelevated work runs as

The admin field picks between the two identities a node offers. It does not name an account, and no field does: the account is a property of the machine, set on the machine.

sudo nobgp config --user deploy

There is deliberately no remote setter — no tool, no app control, nothing over MCP. Changing the identity that gates a channel, through that channel, is using a tool to widen what the tool may do. It is the same reason allow-admin has no remote setter, and it is why every refusal above tells you to go to the box.

Only the node's owner knows which account unprivileged work should run as, so pick one that can actually do the work. Setting user: nobody to satisfy the requirement clears the refusal and buys nothing: a clear failed_precondition naming the problem becomes a scatter of permission failures that name a file.

Unelevated is not the same as unprivileged, and the node says which it is. network_directory reports info.user_is_admin beside info.user: where it is true the configured account is itself administrative — a member of the local Administrators group on Windows — so admin: false there drops from the node's ambient identity to Administrator and no further. That is the common shape on Windows rather than an exotic one, because the installer captures the interactive desktop user. Present-and-false means the node checked and the account is ordinary; absent means nobody checked. Router 0.4.47 and agent 0.4.46 are the releases that report it, and nobgp status answers the same question on the box as allow.unelevated_is_admin.

It is reported, never enforced, and it is not a reason to avoid admin: false — that stays the right choice for work that does not need elevation. It tells you how much the choice is worth on the node you are calling.

A node can refuse admin entirely

allow-admin: false is the node owner's veto on superuser execution, set on the box like the account. It refuses rather than downgrades: an elevated request against it fails with permission_denied instead of silently running as somebody else, and passing the organization's role gate does not clear it. A node that refuses root refuses it to an Owner exactly as it does to a Member.

A node that refuses admin must name an account, or it cannot run anything

This one is the corollary rather than a separate decision, and it is the one worth checking before you narrow a node. allow-admin: false refuses everything elevated, an omitted admin that would run elevated included; admin: "false" is refused wherever it would resolve to root. On a node with no configured account, those two between them leave nothing — no command, no file operation, no terminal session, no dispatched bus command.

# Refuses root, leaves the node fully operable as deploy
sudo nobgp config --allow-admin=false --user=deploy

# Refuses root on a node with no account: nothing can run at all
sudo nobgp config --allow-admin=false

The account must already exist on the machine; nobgp config refuses a name it cannot resolve, and refuses --user root for the same reason the first rule does. On a machine behind CGNAT the way back from the second form is console, RDP or SSH — see Recovering a node you have locked down.

Since agent 0.4.52 the second form asks before it is written, and dropping command from allow-tools — which takes the terminal away too, leaving nothing to get back in with — is refused outright for a non-interactive caller unless it passes --yes. Nothing is saved when a prompt is declined. Confirmed before it is written has the full table.

Why node labels sit with node grants

Labels look like metadata, and mostly they are. But node_grant writes its targets as label pairs — "role=edge,site=irvine" — and targets are evaluated live, on every call. Relabelling a peer therefore moves it into or out of a granted node's reach, immediately, with no grant touched and nobody re-granting anything.

So a grant scoped by labels delegates part of its reach to whoever can apply those labels. That is why node_label carries the same Owner/Admin requirement as node_grant itself: the two tools decide the same thing from opposite ends.

(Separately, the role.* label namespace is reserved and refused by node_label outright, at every role — grants are made with node_grant, not written as labels.)

What a refusal looks like

A role refusal is always the same shape, so you can recognise it without guessing:

{
"code": "forbidden",
"message": "execute.elevated requires a higher role in this organization"
}

Over HTTP it is a 403. There is no retryable key, and its absence is the answer: the flag is sent only when retrying can help. The message names the action, so you can tell which gate you hit:

MessageYou tried to
execute.elevated requires a higher role in this organizationsend admin: true
service.unauthenticated requires a higher role in this organizationturn a service's authentication off
node.role requires a higher role in this organizationlabel a node, or grant/revoke a node role
node.config requires a higher role in this organizationread or change a node's own agent settings
node.rename requires a higher role in this organizationrename a node
network.write requires a higher role in this organizationcreate or delete a network
members.manage requires a higher role in this organizationinvite, remove, or re-role a member, or rename the org
billing.manage requires a higher role in this organizationopen checkout or the billing portal, or set a spend cap
sso.manage requires a higher role in this organizationconfigure or enforce SSO

That is meant literally — nothing about the call will succeed on a second attempt. The remedy is either to drop the field that needed the higher role (admin, auth_required: false), or to have an Owner or Admin make the call.

A not found where you expected forbidden means the tenancy check failed, not the role check: the object belongs to an organization you are not a member of.

All three of the codes you can hit here are 403, and which one you got says whose decision it was:

CodeWhose decisionWhat it means
forbiddenthe router, about youyour role in this organization does not permit the action
permission_deniedthe node, about everyoneone of its owner's vetoes — allow-admin, allow-tools, allow-roots
failed_preconditionthe node, about itselfit is not configured for what was asked — see Execution identity

Only the first is answered by a role change. The other two are answered on the machine, and none of the three is retryable.

Elevated execution is gated twice

admin: true also has to pass the node's own allow-admin setting, which its owner controls on the box. Clearing the organization-role gate does not clear that one. See Owner vetoes and Node access control.