Roles and grants
Customer Connect leans on the central NetFoundry authorization service for every authorization decision. What sits in
this codebase is a small layer on top: three roles (Admin, Read-Only and Member) pre-provisioned on every provider,
customer, and location, plus a thin grants API for handing those roles to identities.
This page explains the model: what a role is, where it lives, how grants cascade, and how the lifecycle is wired into the resource lifecycle.
What a role is
A role is a named bundle of permissions on a specific resource. Customer Connect defines exactly three of them:
| Wire name | Permissions on the target resource |
|---|---|
Admin | read, create, update, delete, connectivity, enroll, and the same on every child |
Read-Only | read, and the same on every child |
Member | read, connectivity, enroll, and the same on every child |
The three values are case-sensitive on the wire and are the only valid name inputs anywhere in the role-grants
surface. Anything else is rejected with 400 Bad Request. Member is additionally rejected on a provider — see
Operators and members below.
Operators and members
The three roles fall into two disjoint populations, and the split is about who the person works for rather than how much they can do:
- Operators —
AdminandRead-Only. These are the provider's own staff. A Provider Admin, a Customer Admin and a Location Admin are the same job at three different scopes; a Customer Admin is not the customer's own administrator but a provider employee whose authority has been narrowed to that one account. - Members —
Member. This is an employee of the provider's end customer, who connects to the applications made available to them. The role carriesread,connectivityandenroll: enough to use the network, never to change its shape.
Each resource exposes the two populations separately — /operators and /members listings — and an identity's operator scope tag in the Identity Service is set when it holds
any operator role across all of its grants.
Because a member belongs to one end customer, Member can only be granted on a customer or a location. Granting it on a provider is rejected with 400 Bad Request:
provider-wide is by definition the provider's own staff.
Beyond create/read/update/delete
Two of the actions in the Admin bundle go past the usual CRUD verbs, and are deliberately kept separate from update so that an operator can be granted one without the other:
connectivitygates pausing and resuming a resource — the.../pauseand.../resumeendpoints on connectors, locations, and customers. It lets an operator suspend or restore traffic on a resource without being able to edit its definition, and vice versa.enrollgates a connector's enrollment material — reissuing an enrollment (POST /connectors/{id}/reissue) and even seeing theenrollmentJwton a connector read response. A caller withreadbut notenrollgets the connector back with the JWT omitted.
Both are included in Admin and excluded from Read-Only, and both cascade to children exactly like the CRUD actions.
Member carries both of these alongside read, on the resource it is granted on and on that resource's children — which is what lets an end customer's employee enrol a
connector and pause or resume it without being able to redefine anything.
Where roles live
Roles attach to the parent resource (a provider, a customer, or a location), not to the identity. An identity gets a role by being granted the role on a specific resource:
Each provider has its own Admin/Read-Only roles; each customer and location has those plus its own Member. They're distinct objects with distinct UUIDs. Granting Admin on customer A gives the identity Admin authority
on customer A and everything beneath it, but says nothing about customer B.
Each named tier — a role granted at a given resource level — has the following scope and capabilities:
| Role | Scope | Can do |
|---|---|---|
| Provider Admin | Entire provider | Read and manage all resources under the provider |
| Provider Read-Only | Entire provider | Read all resources; cannot create, update, or delete |
| Customer Admin | One customer | Read and manage that customer's locations, connectors, and applications |
| Customer Read-Only | One customer | Read that customer's subtree; cannot create, update, or delete |
| Customer Member | One customer | Read that customer's subtree, plus pause/resume and connector enrollment; cannot create, update, or delete |
| Location Admin | One location | Read and manage that location's connectors and applications |
| Location Read-Only | One location | Read that location's subtree; cannot create, update, or delete |
| Location Member | One location | Read that location's subtree, plus pause/resume and connector enrollment; cannot create, update, or delete |
The cascade
Grants on a parent resource implicitly cover its children:
- Granting
Adminon a provider confers Admin authority on that provider, on every customer of the provider, and on everything beneath those customers: every location, connector, application, and access policy. - Granting
Adminon a customer confers Admin authority on that customer, on every location of the customer, and on every connector / application / access policy beneath those locations, but not on the parent provider or its other customers. - Granting
Adminon a location confers Admin authority on that location and on the connectors / applications / access policies beneath it, but not on the parent customer or its other locations. - Granting
Read-Onlyat any level cascades the same way, but only conveysreadactions. - Granting
Memberon a customer or location cascades the same way, conveyingread,connectivityandenroll— the end customer's employee can use and enrol what is beneath the grant, but cannot change its definition.
Practical implication: revoke at the level you granted at. If an identity holds Admin granted at the provider level
and a separate Admin granted at one of that provider's customers, revoking the provider-level grant doesn't take
away the customer-level grant. You'd need to revoke each independently.
Lifecycle
The roles themselves are managed by Customer Connect, not by API callers:
- Creation. When a provider, customer, or location is created, the service creates its
AdminandRead-Onlyroles automatically. The grants API never creates the roles themselves; it only manipulates which identities hold them. - Grants. Identities are granted a role via
POST /providers/{id}/grants,POST /customers/{id}/grants, orPOST /locations/{id}/grants. Grants are additive and idempotent. Re-issuing the same grant confirms the existing state without erroring. An identity can hold bothAdminandRead-Onlysimultaneously; the union of the two is whatever Admin already provides. - Listing.
GET /providers/{id}/grants,GET /customers/{id}/grants, andGET /locations/{id}/grantsreturn every grant currently in force on the resource. Add?identityId=…to filter to a single identity. The role-definition endpoints (/providers/{id}/roles,/customers/{id}/roles,/locations/{id}/roles) describe the two roles themselves; the/grantssub-resources describe who holds them. - Revocation. Revoking via
DELETE /{resource}/{id}/grants?name=…&identityId=…removes every grant of that role on that resource for the given identity. Revoking a role the identity doesn't hold is also idempotent. It returns204 No Content. - Deletion. When a provider, customer, or location is deleted, its roles are cleaned up along with it. Any grants tied to those roles are removed transitively.
What's not here
A few things the role-grants surface deliberately doesn't do:
- No custom roles. The three roles are the entire role catalog. There's no API to define a third role with a different permission bundle. If a use case needs finer-grained permissions, talk to the central authorization service team. Customer Connect is a consumer of that service, not the place to add the capability.
- No identity management. The grants API takes an
identityIdas a UUID and trusts that the identity exists in the central auth system. Creating, listing, or modifying identities themselves is outside this service.
Authorization to use the API
The grants API is itself authorized by the standard auth Customer Connect uses everywhere:
- Listing roles on a provider, customer, or location requires
readon that resource. - Granting and revoking require
updateon that resource. - The cross-resource
GET /grants?identityId=…listing requiresreadon provider.
The auth layer rejects attempts to grant a role the caller couldn't otherwise reach. A caller without update on the
customer can't grant Admin on it.