Skip to content

Show Fields Based on User Permissions

Display different form fields based on user roles and permissions

Control which form fields appear based on user permissions, roles, or any other context. Show admin-only fields to admins, manager fields to managers, and so on.

A form that shows different fields based on user role:

  • Budget approval field (budget approvers only)
  • Team size field (managers only)
  • System configuration (admins only)
  • Basic fields (everyone)
  • Form with linked workflow
  • Understanding of launch workflows

Create a launch workflow to fetch user permissions (workspace/workflows/get_user_permissions.py):

from bifrost import workflow, ExecutionContext
@workflow(name="get_user_permissions", description="Get user permissions for form")
async def get_user_permissions(context: ExecutionContext):
"""Fetch user permissions and roles."""
# Get user roles from your permission system
user_roles = await fetch_user_roles(context, context.user_id)
return {
"is_admin": "admin" in user_roles,
"is_manager": "manager" in user_roles,
"is_budget_approver": "budget_approver" in user_roles,
"user_id": context.user_id,
"user_email": context.email
}
  1. Open form in builder
  2. Right panel → Launch Workflow section
  3. Select get_user_permissions
  4. Save form
  1. Add budget approval field:

    • Field name: budget_amount
    • Type: Number
    • Visibility Expression:
    context.workflow.is_budget_approver === true;
  2. Add team management field:

    • Field name: team_size
    • Type: Number
    • Visibility Expression:
    context.workflow.is_manager === true;
  3. Add system config field:

    • Field name: system_config
    • Type: JSON
    • Visibility Expression:
    context.workflow.is_admin === true;
  4. Add basic field (always visible):

    • Field name: request_description
    • Type: Text Area
    • No visibility expression
  1. Save and launch the form
  2. Form loads launch workflow first
  3. Fields appear based on your permissions
  4. Different users see different fields

Show field if user has ANY of several roles:

context.workflow.is_admin === true || context.workflow.is_manager === true;

Show field if user has ALL roles:

context.workflow.is_admin === true &&
context.workflow.can_approve_budget === true;

Check permissions AND department:

@workflow(name="get_user_context")
async def get_user_context(context: ExecutionContext):
user = await get_user_details(context, context.user_id)
return {
"is_manager": user.role == "manager",
"department": user.department,
"permissions": user.permissions
}

If your permission system returns arrays:

@workflow(name="get_permissions")
async def get_permissions(context: ExecutionContext):
perms = await fetch_permissions(context, context.user_id)
return {
"permissions": perms, # ["read", "write", "admin"]
"departments": await get_departments(context, context.user_id)
}

Check if array contains specific permission:

context.workflow.permissions.includes("admin");

Check if user has access to specific department:

context.workflow.departments.includes("engineering");

Check if user has ANY of several permissions:

["admin", "manager"].some((perm) =>
context.workflow.permissions.includes(perm)
);

Mix launch workflow data with field values:

// Show field if admin OR if requesting for self
context.workflow.is_admin === true ||
context.field.user_id === context.workflow.user_id;
// Show approval field only for high budget + approver role
context.field.budget > 10000 && context.workflow.can_approve_budget === true;

Pass context to permission check:

@workflow(name="check_resource_access")
@param("resource_id", type="string", required=True)
async def check_resource_access(context: ExecutionContext, resource_id: str):
has_access = await check_access(
context,
context.user_id,
resource_id
)
return {
"has_access": has_access,
"resource_id": resource_id
}

Group multiple admin fields with same visibility:

// Apply to all admin fields
context.workflow.is_admin === true;

Show different fields per tier:

@workflow(name="get_user_tier")
async def get_user_tier(context: ExecutionContext):
user = await get_user(context, context.user_id)
return {
"tier": user.subscription_tier, # "free", "pro", "enterprise"
"features": user.enabled_features
}
// Show pro feature field
context.workflow.tier === "pro" || context.workflow.tier === "enterprise";
// Show enterprise-only field
context.workflow.tier === "enterprise";
// Show if specific feature enabled
context.workflow.features.includes("advanced_reporting");

Make fields conditionally required:

  1. Set field as not required in settings
  2. Add visibility rule to show when needed
  3. Validate in workflow:
@workflow(name="process_request")
async def process_request(
context: ExecutionContext,
request_type: str,
approval_notes: str = None
):
# Check if approval notes required
if request_type == "high_priority" and not approval_notes:
return {
"success": False,
"error": "Approval notes required for high priority requests"
}
# Process request
return {"success": True}
  1. Test launch workflow independently:

    • Click Play button next to Launch Workflow in form builder
    • Click Execute
    • Verify returned permissions are correct
  2. Check context in browser:

    • Open form
    • Open DevTools → Console
    • Type: window.formContext.workflow
    • Verify permissions loaded correctly
  3. Test with different users:

    • Log in as user with different roles
    • Verify correct fields appear
    • Check all permission combinations

Fields not appearing: Verify launch workflow returns expected data. Check browser console for context.workflow object.

All fields hidden: Expression may have syntax error. Check browser console for JavaScript errors.

Fields show for wrong users: Review permission logic in launch workflow. Test workflow independently.

// Equality
context.workflow.is_admin === true;
context.workflow.role === "manager";
// Inequality
context.workflow.status !== "inactive";
// Greater than / less than
context.workflow.access_level > 5;
// AND - both must be true
condition1 && condition2;
// OR - either can be true
condition1 || condition2;
// NOT - invert condition
!context.workflow.is_disabled;
// Check if array contains value
context.workflow.permissions
.includes("admin")
[
// Check if any match
("admin", "manager")
].some((role) => context.workflow.roles.includes(role))
[
// Check if all match
("read", "write")
].every((perm) => context.workflow.permissions.includes(perm));

Always check for null/undefined when values might be missing:

// Safe check
context.workflow.department && context.workflow.department === "engineering";
// Optional chaining
context.workflow.department?.length >
0(
// Default value
context.workflow.role || "user"
) ===
"admin";
  1. Keep launch workflows fast - They block form load
  2. Return clear permission flags - Boolean values are easiest to check
  3. Test all permission combinations - Verify each role sees correct fields
  4. Document permission requirements - Add comments explaining complex rules
  5. Use meaningful permission names - is_budget_approver vs perm_ba
  6. Handle missing data - Always check for null/undefined