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.
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.
Admins can always execute all workflows, regardless of the permissions configuration.
Default behavior
permissions value | Who 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 |
- 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
policyis 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
| Context | Resolves to |
|---|---|
user | The executing user's properties (from the _user blueprint) |
userTeams | The executing user's team properties (from the _team blueprint) |
form | The workflow trigger's form input values |
Dot notation for entity inputs
For entity-type form inputs, use dot notation to access entity properties:
| Syntax | Type |
|---|---|
inputName | string |
inputName.$identifier | string |
inputName.$title | string |
inputName.$team | array - use contains/notContains |
inputName.propertyName | actual blueprint type |
Deep traversal (input.relation.nested) is not supported, use mirror or calculation properties instead.
Operators
| Operator | Description |
|---|---|
= | Equals |
!= | Not equals |
>, <, >=, <= | Comparisons (numbers/strings) |
in | Scalar property is in array value |
notIn | Scalar property is not in array value |
contains | Array property contains scalar value (use for $team) |
notContains | Array property does not contain scalar value |
containsAny | Array property shares at least one element with another array value |
empty | Value is empty |
notEmpty | Value 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"
}
]
}
}
}
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"]
}
]
}
}
}
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"]
}
]
}
}
}
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.