Authorization
vNext authorization makes decisions about triggering transitions, querying instances/states and master schema field visibility through a single shared model. This page is the single source of truth for authorization; the workflow, schema and function pages reference it whenever they need authorization.
Authorization rests on two inputs:
- Token claims — the identity of the requester (
sub,act_sub). - Role grants —
allow/denyrules on a transition, queryRole or schema field.
In all grant evaluations, DENY always overrides ALLOW. If an actor matches both allow and deny, the result is deny.
Token Claims: sub and act_sub
vNext uses two claims to distinguish "on-behalf-of" scenarios:
| Claim | Meaning |
|---|---|
sub | The customer on whose behalf the operation is performed (subject) |
act_sub | The user performing the operation (actor) |
For example, when a call-center agent starts an operation on behalf of a customer: act_sub is the agent's identity, sub is the customer's identity. In self-service use they may be the same.
This distinction is decisive both in system roles (actor or subject?) and in JSONPath grants ($user vs $userBehalfOf).
Predefined System Roles
For instance authorization (transition roles, state/flow queryRoles, or master schema field visibility), four static system roles are available. They resolve at runtime based on the instance context:
| Role | Resolved identity | Description |
|---|---|---|
$InstanceStarter | Actor | The user who started the instance |
$PreviousUser | Actor | The user who triggered the previous transition |
$InstanceBehalfOfStarter | Subject | The subject who started the instance (on-behalf-of token) |
$PreviousBehalfOfUser | Subject | The subject of the previous transition (on-behalf-of token) |
The first two compare against act_sub (actor), the last two against sub (subject).
roleGrant example:
{
"roles": [
{ "role": "$InstanceStarter", "grant": "allow" },
{ "role": "$PreviousUser", "grant": "allow" }
]
}
Instance Data JSONPath Authorization
The role values inside roles may use JSONPath-style expressions. The runtime compares token values against context values read from ScriptContext (including Instance.Data). This enables dynamic authorization bound to instance data instead of static role lists.
| Prefix | Compared token | Compared context value |
|---|---|---|
$user.<jsonpath> | Actor (act_sub) | The <jsonpath> value in context |
$userBehalfOf.<jsonpath> | Subject (sub, on-behalf-of) | The <jsonpath> value in context |
$role.<jsonpath> | Role | The <jsonpath> value in context |
Example paths (must match your workflow data schema):
$user.$.context.Instance.Data.customer.ownerUserId
$user.$.context.Instance.Data.assignedUsers[*].userId
$userBehalfOf.$.context.Instance.Data.customer.behalfOfUserId
$role.$.context.Instance.Data.permissions.requiredRole
$role.$.context.Transition.Key
These patterns are evaluated everywhere available transition and data authorization applies (including master schema field visibility).
Reference: vnext#469
Master Schema Field-Level Visibility
A flow's master schema can apply field-level visibility by defining the x-roles keyword on schema properties — i.e. it provides column-level security. The Data Function and data-returning endpoints (Get Instance, GetInstances, etc.) run the authorize layer and return only the fields the caller is allowed to see.
Note:
rolesandqueryRolesare for transition and state authorization. Schema property field visibility uses thex-roleskeyword (same shape:role+grant).
- Properties without an
x-rolesdefinition are visible to all authorized callers. - Properties with
x-rolesuse the same system roles and JSONPath grants;rolemay be a static name or a JSONPath expression,grant∈allow|deny(DENY > ALLOW). - For structure and examples, see Schema → Field-Level Authorization:
x-rolesand Schema Definition →x-roles. - The keyword is defined in
vnext-schemaview-vocab.json.
For master schema behavior and why required should not be used, see Schema → Master Schema Behavior.
Grant evaluation: allow-list vs. deny-only (blacklist)
The intent of a roles / queryRoles set is interpreted in two ways depending on its grants:
| Set contents | Mode | Default | Meaning |
|---|---|---|---|
Contains at least one allow grant | allow-list (whitelist) | deny | Only matching allow roles pass |
Contains only deny grants | blacklist | allow | Everyone is allowed except the listed roles |
In both modes DENY always overrides ALLOW. A deny-only set lets you express "allow everyone except X" without enumerating every permitted role.
:::warning Backward impact
An existing deny-only set is now treated as a blacklist (open to everyone except the listed roles). If your intent was "deny everyone," convert it to an allow-list by adding at least one allow grant.
:::
Where Is It Evaluated?
| Context | Field | Effect |
|---|---|---|
| Transition | roles | Who can trigger the transition |
| Flow / State | queryRoles | Who can query instances and states (state level overrides root). Enforced by the built-in state/data/view/schema read functions on the current state; 403 if not allowed |
State alias | roles | The role-masked view of a state |
| Master schema property | x-roles | Column-level data visibility |
Related
- Workflow component —
queryRoles, transitionroles, statealias - Schema component — master schema and field-level visibility
- Built-in Functions — State/Data Function authorization behavior and authorize endpoints
- Instance Data —
Instance.Dataand ScriptContext