Skip to main content

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:

  1. Token claims — the identity of the requester (sub, act_sub).
  2. Role grantsallow / deny rules on a transition, queryRole or schema field.
DENY takes precedence

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:

ClaimMeaning
subThe customer on whose behalf the operation is performed (subject)
act_subThe 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:

RoleResolved identityDescription
$InstanceStarterActorThe user who started the instance
$PreviousUserActorThe user who triggered the previous transition
$InstanceBehalfOfStarterSubjectThe subject who started the instance (on-behalf-of token)
$PreviousBehalfOfUserSubjectThe 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.

PrefixCompared tokenCompared 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>RoleThe <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: roles and queryRoles are for transition and state authorization. Schema property field visibility uses the x-roles keyword (same shape: role + grant).

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 contentsModeDefaultMeaning
Contains at least one allow grantallow-list (whitelist)denyOnly matching allow roles pass
Contains only deny grantsblacklistallowEveryone 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?

ContextFieldEffect
TransitionrolesWho can trigger the transition
Flow / StatequeryRolesWho 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 aliasrolesThe role-masked view of a state
Master schema propertyx-rolesColumn-level data visibility