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.
What You’ll Build
Section titled “What You’ll Build”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)
Prerequisites
Section titled “Prerequisites”- Form with linked workflow
- Understanding of launch workflows
Create Permission Check Workflow
Section titled “Create Permission Check Workflow”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 }@workflow(name="get_user_permissions")async def get_user_permissions(context: ExecutionContext): """Simple permission check using built-in platform admin flag.""" return { "is_admin": context.is_platform_admin, "user_id": context.user_id }Configure Form Launch Workflow
Section titled “Configure Form Launch Workflow”- Open form in builder
- Right panel → Launch Workflow section
- Select
get_user_permissions - Save form
Add Fields with Visibility Rules
Section titled “Add Fields with Visibility Rules”-
Add budget approval field:
- Field name:
budget_amount - Type: Number
- Visibility Expression:
context.workflow.is_budget_approver === true; - Field name:
-
Add team management field:
- Field name:
team_size - Type: Number
- Visibility Expression:
context.workflow.is_manager === true; - Field name:
-
Add system config field:
- Field name:
system_config - Type: JSON
- Visibility Expression:
context.workflow.is_admin === true; - Field name:
-
Add basic field (always visible):
- Field name:
request_description - Type: Text Area
- No visibility expression
- Field name:
Test It
Section titled “Test It”- Save and launch the form
- Form loads launch workflow first
- Fields appear based on your permissions
- Different users see different fields
Advanced Patterns
Section titled “Advanced Patterns”Multiple Permission Checks
Section titled “Multiple Permission Checks”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;Department-Scoped Visibility
Section titled “Department-Scoped Visibility”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 }context.workflow.is_manager === true &&context.workflow.department === "engineering"Permission Array Checks
Section titled “Permission Array Checks”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));Combine with Field Values
Section titled “Combine with Field Values”Mix launch workflow data with field values:
// Show field if admin OR if requesting for selfcontext.workflow.is_admin === true || context.field.user_id === context.workflow.user_id;// Show approval field only for high budget + approver rolecontext.field.budget > 10000 && context.workflow.can_approve_budget === true;Parameterized Permissions
Section titled “Parameterized Permissions”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 }Create hidden field resource_id, enable “Allow as Query Parameter”, then pass via URL: /execute/form?resource_id=res-123
context.workflow.has_access === trueCommon Patterns
Section titled “Common Patterns”Admin-Only Section
Section titled “Admin-Only Section”Group multiple admin fields with same visibility:
// Apply to all admin fieldscontext.workflow.is_admin === true;Tiered Access
Section titled “Tiered Access”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 fieldcontext.workflow.tier === "pro" || context.workflow.tier === "enterprise";
// Show enterprise-only fieldcontext.workflow.tier === "enterprise";
// Show if specific feature enabledcontext.workflow.features.includes("advanced_reporting");Conditional Required Fields
Section titled “Conditional Required Fields”Make fields conditionally required:
- Set field as not required in settings
- Add visibility rule to show when needed
- 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}Testing Visibility
Section titled “Testing Visibility”-
Test launch workflow independently:
- Click Play button next to Launch Workflow in form builder
- Click Execute
- Verify returned permissions are correct
-
Check context in browser:
- Open form
- Open DevTools → Console
- Type:
window.formContext.workflow - Verify permissions loaded correctly
-
Test with different users:
- Log in as user with different roles
- Verify correct fields appear
- Check all permission combinations
Troubleshooting
Section titled “Troubleshooting”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.
Expression Reference
Section titled “Expression Reference”Basic Comparisons
Section titled “Basic Comparisons”// Equalitycontext.workflow.is_admin === true;context.workflow.role === "manager";
// Inequalitycontext.workflow.status !== "inactive";
// Greater than / less thancontext.workflow.access_level > 5;Logical Operators
Section titled “Logical Operators”// AND - both must be truecondition1 && condition2;
// OR - either can be truecondition1 || condition2;
// NOT - invert condition!context.workflow.is_disabled;Array Operations
Section titled “Array Operations”// Check if array contains valuecontext.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));Null Safety
Section titled “Null Safety”Always check for null/undefined when values might be missing:
// Safe checkcontext.workflow.department && context.workflow.department === "engineering";
// Optional chainingcontext.workflow.department?.length > 0( // Default value context.workflow.role || "user" ) === "admin";Best Practices
Section titled “Best Practices”- Keep launch workflows fast - They block form load
- Return clear permission flags - Boolean values are easiest to check
- Test all permission combinations - Verify each role sees correct fields
- Document permission requirements - Add comments explaining complex rules
- Use meaningful permission names -
is_budget_approvervsperm_ba - Handle missing data - Always check for null/undefined
Next Steps
Section titled “Next Steps”- Cascading Dropdowns - Dynamic dropdowns based on selections
- HTML Content - Display dynamic permission-based content
- Startup Workflows - Complete launch workflow reference