Skip to main content

Check out Port for yourself ➜ 

Permissions

Workflow permissions allow you to control who can see and execute a workflow from Port's self-service page. Workflows that a user does not have permission to execute are hidden entirely from their self-service page.

Related documentation

This page covers workflow-specific execute permissions. For general Port RBAC, see manage users & teams.

Common use cases

  • Allow only members of a specific team to execute a workflow.
  • Restrict a workflow to Admin only.
  • Dynamically grant access based on the user's properties (e.g., department, team).
  • Allow access only when a specific form input value is provided.

How it works

Permissions are set in the trigger node's config when creating or updating a workflow via POST /workflows or PUT /workflows/:id.

Admin always has access

Admins can always execute all workflows, regardless of the permissions configuration.

Default behavior

permissions valueWho can execute
Not set or {}Admin only
{ "roles": ["Member"] }Admin + Member
{ "users": [...] }Admin + listed users
{ "teams": [...] }Admin + listed teams
{ "policy": {...} }Admin + users matching the policy
Evaluation order
  • Static fields (roles, users, teams) are checked first using OR logic. Any match grants access.
  • Policy is only evaluated if static fields don't match.
  • Machine tokens bypass static checks when no policy is present.

Configuration

Permissions are set inside the trigger node's config object:

{
"identifier": "my-workflow",
"title": "My Workflow",
"nodes": [
{
"identifier": "trigger",
"title": "Start",
"config": {
"type": "SELF_SERVE_TRIGGER",
"permissions": {
"roles": ["Member"],
"users": [],
"teams": []
},
"userInputs": {
"properties": {}
}
}
}
],
"connections": []
}

Static assignment

Grant access to specific roles, users, or teams. Use Port user IDs (not emails).

{
"permissions": {
"roles": ["Member"],
"users": ["user-id-1", "user-id-2"],
"teams": ["platform-team", "sre-team"]
}
}

Admin only

Two ways to restrict to Admin only:

Explicit empty object:

{
"permissions": {}
}

Omit the field:

{
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": { "properties": {} }
}
}

Dynamic permissions (policy)

Use policy for runtime evaluation based on user properties, team membership, or form inputs.

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "user", "property": "department" },
"operator": "=",
"value": "engineering"
}
]
}
}
}

The policy object provides an additional access path beyond static fields.

Policy structure

{
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "<context>", "property": "<property>" },
"operator": "<operator>",
"value": "<value>"
}
]
}
}

Contexts

ContextResolves to
userThe executing user's properties (from the _user blueprint)
userTeamsThe executing user's team properties (from the _team blueprint)
formThe workflow trigger's form input values

Dot notation for entity inputs

For entity-type form inputs, use dot notation to access entity properties:

SyntaxType
inputNamestring
inputName.$identifierstring
inputName.$titlestring
inputName.$teamarray - use contains/notContains
inputName.propertyNameactual blueprint type

Deep traversal (input.relation.nested) is not supported, use mirror or calculation properties instead.

Operators

OperatorDescription
=Equals
!=Not equals
>, <, >=, <=Comparisons (numbers/strings)
inScalar property is in array value
notInScalar property is not in array value
containsArray property contains scalar value (use for $team)
notContainsArray property does not contain scalar value
containsAnyArray property shares at least one element with another array value
emptyValue is empty
notEmptyValue is not empty

Examples

Allow only a specific team (static)

{
"permissions": {
"teams": ["platform-team"]
}
}

Allow based on team membership (policy)

Only allow users who are a member of the platform-team team (requires $identifier property on the _team blueprint):

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "userTeams", "property": "$identifier" },
"operator": "contains",
"value": "platform-team"
}
]
}
}
}

Restrict to members of entity's owning team

Only allow users who belong to the same team that owns the selected service entity:

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "form", "property": "service.$team" },
"operator": "containsAny",
"value": { "context": "userTeams", "property": "$identifier" }
}
]
}
}
}

Restrict based on entity team ownership

Only allow when the selected cluster entity belongs to platform-team:

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "form", "property": "cluster.$team" },
"operator": "contains",
"value": "platform-team"
}
]
}
}
}

Restrict based on form input

Only allow when user selects production environment:

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "form", "property": "environment" },
"operator": "=",
"value": "production"
}
]
}
}
}

Restrict based on user property

Only allow users in the engineering department (requires department property on _user blueprint):

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "user", "property": "department" },
"operator": "=",
"value": "engineering"
}
]
}
}
}

Restrict to specific entity

Only allow when a specific cluster is selected (requires cluster entity input):

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "form", "property": "cluster.$identifier" },
"operator": "=",
"value": "prod-cluster"
}
]
}
}
}

Combined static + policy

The member role always has access. Non-members need to be in the SRE department:

{
"permissions": {
"roles": ["Member"],
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "user", "property": "department" },
"operator": "=",
"value": "sre"
}
]
}
}
}
Evaluation order

Static fields are checked first. Policy only runs if static fields don't match.

Multiple conditions (OR)

Allow if the user is in the engineering or SRE department:

{
"permissions": {
"policy": {
"combinator": "or",
"rules": [
{
"property": { "context": "user", "property": "department" },
"operator": "=",
"value": "engineering"
},
{
"property": { "context": "user", "property": "department" },
"operator": "=",
"value": "sre"
}
]
}
}
}

Or use in operator for cleaner syntax:

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "user", "property": "department" },
"operator": "in",
"value": ["engineering", "platform", "sre"]
}
]
}
}
}

Restrict to members of entity's owning team (dynamic)

Allow execution only if the executing user belongs to one of the teams that own the selected entity. Requires an entity-type form input (e.g., service).

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "form", "property": "service.$team" },
"operator": "containsAny",
"value": { "context": "userTeams", "property": "$identifier" }
}
]
}
}
}

form.service.$team resolves to the array of teams that own the selected service entity. userTeams.$identifier resolves to the array of all team identifiers the executing user belongs to. The rule passes if those two arrays share at least one element.


Restrict to managers of team-owned entities

Allow execution only if the executing user is the manager of the team that owns the selected entity.

Add a mirror property to your blueprint that follows the relation path to the manager's identifier (e.g., service -> _team -> manager(_user) -> $identifier), then compare it against the executing user's identity:

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
// Mirror property follows: service -> _team -> manager (_user) -> $identifier
"property": { "context": "form", "property": "service.team_manager_id" },
"operator": "=",
"value": { "context": "user", "property": "$identifier" }
}
]
}
}
}

form.service.team_manager_id resolves to the manager's email (via the mirror property). user.$identifier resolves to the executing user's email. The rule passes only if they match.


Restrict to managers or team leads

Allow execution only if the executing user has a specific role. Requires a role (or equivalent) property on the _user blueprint:

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
"property": { "context": "user", "property": "role" },
"operator": "in",
"value": ["manager", "team-lead", "director"]
}
]
}
}
}
Blueprint properties

The properties available in the user and userTeams contexts depend on what properties you have defined on your _user and _team blueprints. You can add custom properties such as role, department, or is_manager to those blueprints and use them in workflow permissions.


Restrict to senior roles

Allow execution only for senior engineers (for example, to gate production deployments):

{
"permissions": {
"policy": {
"combinator": "and",
"rules": [
{
// Requires a 'seniority' property on the _user blueprint
"property": { "context": "user", "property": "seniority" },
"operator": "in",
"value": ["senior", "staff", "principal"]
}
]
}
}
}
Validation vs permissions

If you want to block execution based on catalog state (for example, preventing a workflow from running if an entity with the given name already exists), that is a runtime validation, not a permissions check. Use a condition node as the first step in your workflow to query the catalog and stop the run if the condition is not met.