Execution Roles & Assume-Role
Pin a curated execution role to a pipeline or report so a low-privilege caller can opt a single run into exactly the permissions that job needs — least privilege with no standing elevation, fully audited, and tamper-resistant.
Execution roles let a pipeline or report run under a curated, admin-controlled permission set instead of the caller's own permissions — for the duration of a single run, with no lasting change to the caller. They exist so that automated and shared workloads can follow least privilege: a job gets exactly the access it needs, nobody accumulates standing elevation, and every run is auditable. This page is for administrators who design privileged, shared workflows.
The problem this solves
In most platforms, an automated or shared job runs with whatever permissions the user or API key that launched it happens to hold. That forces a bad trade-off:
- Over-grant the caller — permanently give analysts (or an integration key) the elevated access a trusted job needs, so they can run it. Now that standing access exists everywhere, all the time, whether the job is running or not.
- Or block them — refuse to let low-privilege users run curated work at all, and route every request through an admin.
Neither is acceptable for finance-grade or regulated data. Execution roles remove the trade-off: the resource carries the elevated permission, not the person, and only while it runs.
How it works
An administrator pins an execution role to a resource. An authorized caller then opts a single run into assuming that role's permissions:
POST /api/pipelines/{id}/start { "assume_role": true }
POST /api/pipelines/{id}/test { "assume_role": true }
POST /api/reports/{id}/execute { "assume_role": true }
The flow is intentionally strict, and the order of checks matters:
- Normal access check first. Assume-role never bypasses the resource's own run gate. You must already be allowed to run the pipeline or report on your own permissions. Assume-role decides what the run can reach once started — it is not a way to run something you couldn't otherwise run.
- Role must be assigned. If the resource has no execution role bound, an
assume_role: truerequest returns400. An administrator must bind a role first — there is no implicit or default elevation. - Permission swap for the run. For the duration of that one run, the caller's permission set is replaced by the execution role's permissions. When the run ends, nothing about the caller's standing access has changed.
The result: a low-privilege caller can safely run a curated, high-trust resource — for example a report that reads a restricted finance connection — without ever being granted those elevated permissions to hold and misuse elsewhere.
Permissions only — never an identity swap
This is the most important property to understand, and it is a hard design invariant.
Assume-role grants permissions only. It does not change whose data the run touches or which credentials are used:
- Data still flows through the resource's configured bridges on their service credentials, exactly as a normal run would. Assuming a role changes authorization, never identity.
- The run's identity context is unchanged, so bridge and per-user credential isolation are fully preserved. A user cannot use assume-role to reach another user's personal connection — that path does not exist in any mode (see Connections & Isolation).
- There is no parameter, anywhere, that names whose credentials to use. The execution role is an authorization grant, full stop.
Automated runs behave identically. API keys and OAuth apps can carry roles and pass assume_role; scheduled and webhook-triggered runs record the assumed role for audit while data access continues through service credentials.
Scoping the execution role
An execution role is an ordinary role, so it can — and usually should — be scoped to exactly the resources the job needs. Scopes use the same JSON shape as any grant, with ["*"] matching any resource of a type:
{
"pipelines": ["<id>", "..."],
"reports": ["<id>", "..."],
"collections": ["<id>", "..."],
"bridges": ["<name>", "..."],
"tools": ["<name>", "..."]
}
Because collection scope is enforced on data execution, a finance execution role can be narrowed to a single restricted collection — the run gets exactly the data it needs and nothing adjacent. Build the execution role as tightly as the job allows; a broad execution role defeats the purpose. See Roles & Permissions for the full scoping model.
Auditability
Every assume-role run is attributable end to end. The run record captures which role was assumed, alongside the triggering identity, timing, and status — for interactive, scheduled, and webhook-triggered runs alike. That means an auditor can answer, for any privileged execution: who launched it, what elevated role it ran under, when, and what it touched. Elevation is never anonymous and never implicit; it is a recorded event tied to a named principal and a named role. See Auditing & Telemetry for how these records are queried.
Admin edit-lock
To keep the role-to-resource binding tamper-resistant, Nexus enforces an edit-lock:
- Binding is admin-only. Setting or changing a resource's execution role requires an administrator.
- The resource then locks to admins. Once a pipeline or report carries an execution role, updating or deleting it is also administrator-only.
This closes the obvious attack: a non-admin author cannot bind a curated privileged role to a pipeline and then quietly rewrite the pipeline's code to abuse that role. The author who runs under the role cannot change what the role does or what the code does — the admin-controlled binding stays the security boundary. See the edit-lock section in Roles & Permissions.
Behavior reference
| Situation | Result | Resolution |
|---|---|---|
assume_role: true on a resource with no execution role |
400 |
An administrator binds an execution role first |
| Caller not otherwise allowed to run the resource | Denied (normal gate) | Grant run permission; assume-role does not bypass it |
| Non-admin tries to set, update, or delete a resource that carries an execution role | 403 |
An administrator performs the change |
| A scoped execution role does not cover the requested collection/resource | 403 |
Widen the execution role's scope |
| The assigned execution role is deleted | The binding is cleared automatically; later assume-role requests return 400 |
Reassign a role |
When to use them
- Let analysts or apps run a sensitive, vetted pipeline or report without granting standing access to the underlying data.
- Give an API key or scheduled job a precise, auditable permission set scoped to just the resources it runs, instead of a broad role.
- Keep a tamper-resistant boundary between who authors a resource and what permissions it executes with.
When not to use them
- If the caller should genuinely hold the permission all the time, just grant the role directly — don't add indirection.
- Execution roles do not change data custody or credentials, so they are not a tool for cross-user data sharing. Use service bridges for shared data.