Portal Community

Permission String Format

All permissions follow the pattern resource.action (using dot notation). The resource identifies the capability domain; the action identifies what operation is being authorized.

// Format: resource.action
"workflow.design"        // can create/edit workflow definitions
"workflow.initiate"      // can start a workflow instance
"workflow.view"          // can read workflow status and history
"workflow.cancel"        // can cancel a running workflow instance

"form.create"            // can create new form definitions
"form.edit"              // can modify existing form definitions
"form.publish"           // can publish a form to users
"form.submit"            // can submit a form
"form.view"              // can read form definitions and submissions

"iam.user.manage"        // can create/edit/delete users
"iam.role.assign"        // can assign roles to users
"iam.policy.manage"      // can create/edit security policies

"audit.read"             // can read audit logs
"audit.export"           // can export audit data

"report.finance.read"    // custom domain permission — finance reports
"report.payroll.read"    // custom domain permission — payroll reports

Wildcard Permissions

A trailing .* wildcard grants all actions on a resource. Wildcards are only available to system roles — tenant custom roles must enumerate specific permissions.

"workflow.*"   // all workflow operations (admin only)
"form.*"       // all form operations (admin only)
"iam.*"        // all IAM operations (admin only)
"tenant.*"     // all tenant management operations (admin only)

IPermissionProvider

public interface IPermissionProvider
{
    /// <summary>
    /// Returns the list of permission keys for a user.
    /// Returns null if HttpContext is unavailable (background jobs) — treat as "no permissions".
    /// Returns empty list if user has no explicit permissions.
    /// </summary>
    Task<IReadOnlyList<string>?> GetUserPermissionsAsync(
        string userId,
        string tenantId,
        CancellationToken ct);
}

// BizFirst Passport implementation — reads from JWT "permissions" claim
// or falls back to SQL IAM_UserPermissions table for explicit grants

Full Permission Reference

PermissionResourceDescription
workflow.designFlow StudioCreate and edit workflow definitions in Flow Studio
workflow.initiateFlow StudioStart a new workflow instance
workflow.viewFlow StudioRead workflow status, history, and logs
workflow.cancelFlow StudioCancel a running workflow instance
workflow.adminFlow StudioAdministrative workflow operations (replay, force-complete)
form.createAtlas FormsCreate new form definitions
form.editAtlas FormsModify existing form definitions
form.publishAtlas FormsPublish forms to make them available to users
form.submitAtlas FormsSubmit a form instance
form.viewAtlas FormsRead form definitions and submission data
iam.user.managePassport IAMCreate, update, and disable user accounts
iam.role.assignPassport IAMAssign and revoke roles from users
iam.policy.managePassport IAMCreate and manage security policies
audit.readAuditRead security and activity audit logs
audit.exportAuditExport audit data to external systems
managed-identity.managePassportCreate and manage managed identities
task.completeWorkDeskComplete HIL tasks assigned to the user

Defining Custom Permissions

POST /passport/admin/permissions
Authorization: Bearer {admin-token}
Content-Type: application/json

{
  "permissionKey": "report.finance.read",
  "displayName": "Read Finance Reports",
  "description": "Allows access to financial reporting dashboards",
  "resourceDomain": "report",
  "tenantId": "tenant-abc"
}

// Custom permissions can then be assigned to tenant roles
// or checked at runtime using IPassportClient.CheckPermissionAsync()
Permission Strings vs. Role Checks

Prefer checking permissions over checking roles in application code. Permission checks are more resilient to role restructuring — if you refactor which roles have which permissions, code that checks workflow.design continues to work correctly, while code that checks role == "manager" may break.