Business Roles¶
Learn how Business Roles work and best practices for managing user access in Forge applications.
π Overview¶
Business Roles are the foundation of user access management in Forge applications. They represent organizational identities that bridge the gap between your company's structure and application permissions.
What is a Business Role?¶
A Business Role is a security group in your identity provider that aggregates users sharing an organizational position. Business Roles provide a logical name that applications can reference without knowing how membership is derived.
Key Concept: Corporate Business Roles are populated from user profile attributes synced from on-premises AD (division and job title). External Business Roles are populated from Okta group membership. Either way, users who match automatically receive the Business Role.
Examples:
| Business Role Name | Populated From |
|---|---|
Claims Adjuster |
Claims Division β job titles Claims Adjuster I, II, etc. |
Finance Analyst |
Finance Division β job titles Financial Analyst, Senior Analyst |
Premium Auditor |
Audit Division β job titles Premium Auditor, Senior Auditor |
HR Manager |
HR Division β job titles HR Manager, Senior HR Manager |
Uniqueness Required
Business Roles must be unique across the entire organization. Each Business Role name can only exist once in the identity system.
Create Before Use
Business Roles must be created in the business roles repository before they can be referenced in your application's auth configuration. You cannot use a Business Role that doesn't exist.
How Business Roles Work¶
User's Organization Position β Assigned Business Role β Granted App Roles β Application Access
(Claims Department, Adjuster) (Claims Adjuster) (App.Read, App.Write) (Can use features)
The Flow:
- Assignment: User is assigned Business Roles based on organizational position
- Mapping: Applications define which Business Roles can access them
- Permissions: Each Business Role is granted specific App Roles (permissions)
- Access: Users automatically receive App Roles from their Business Roles
Corporate vs. External Business Roles¶
Forge distinguishes between two types of Business Roles:
| Aspect | Details |
|---|---|
| Who | Employees and internal staff |
| Identity Provider | Microsoft Entra ID |
| Storage | Entra ID security groups |
| Created In | {Project}-okta-business-roles-corp Azure DevOps repo |
| Deployed | Organization-wide (any app can use) |
| Used In | infra/auth/corp/config.yml (in your app repo) |
| Examples | Claims Adjuster, Finance Analyst, Premium Auditor |
| Aspect | Details |
|---|---|
| Who | Policyholders, injured workers, employers, providers |
| Identity Provider | Okta |
| Storage | Okta groups |
| Created In | {Project}-okta-business-roles-external Azure DevOps repo |
| Deployed | Organization-wide (any app can use) |
| Used In | infra/auth/ext/user/business-role-app-role.yml (in your app repo) |
| Examples | Policy Holder, Injured Worker, Employer Representative |
π·οΈ Terminology Reference¶
| Term | Also Known As | Description |
|---|---|---|
| Business Role | External Role, User Role | Organizational position (Division + Title) |
| App Role | App Permission, Role | Permission within your application |
| Scope | API Scope | Permission for app-to-app calls on behalf of user |
The platform also manages one user-delegation scope per provider; Authorization owns those names.
Key Distinctions¶
- Business Role vs. App Role: Business Role = organizational position; App Role = what they can do in your app
- App Role vs. Scope: App Role = user permissions; Scope = app-to-app permissions on behalf of user
π‘ Best Practices¶
β Do's¶
| Practice | Reason |
|---|---|
| Use descriptive names | Finance Analyst is clearer than FA01 |
| Follow naming convention | Use Division Title format consistently |
| Ensure uniqueness | No duplicate Business Roles across organization |
| Document ownership | Know which team owns each Business Role |
| Regular reviews | Audit memberships periodically |
| Principle of least privilege | Grant minimum App Roles needed |
β Don'ts¶
| Anti-Pattern | Why to Avoid |
|---|---|
| Application-specific Business Roles | Business Roles should be organization-wide |
Generic names (User, Admin) |
Too vague, leads to over-permissioning |
| Mixing concerns | Don't create roles based on app access needs |
| Excessive proliferation | Reuse existing roles when possible |
| Over-granting permissions | Manager β admin access to everything |
π Example Scenarios¶
Scenario 1: New Employee Joins¶
- User is assigned
Claims AdjusterBusiness Role - Your app has
Claims Adjustermapped to[App.Read, App.Write] - User automatically gets those permissions
- No manual access grant needed
Scenario 2: External User Access¶
- Injured worker is assigned
Injured WorkerBusiness Role (external) - Your app maps
Injured Workerto[App.Read] - Injured worker gets read-only access to their claim
- Clearly separated from corporate users
Scenario 3: Department Change¶
- User moves from Claims to Finance
- Business Role changes:
Claims AdjusterβFinance Analyst - User automatically loses Claims permissions, gains Finance permissions
- No app configuration changes needed
βοΈ Creating Business Roles¶
Business Roles are created in dedicated Azure DevOps repositories, separate from your application. Once created, they are deployed organization-wide and can be used by any application across teams.
Find Your Project's Repo First¶
Don't create a second repo for a workspace tag that already has one
Business roles repos map one-to-one to a Terraform Cloud workspace, tagged
<teamname-lowercase>-busrole-corp or <teamname-lowercase>-busrole-external. The tag comes
from both the team name and the tenant, so a team is expected to have two repos: one corp and
one external. Creating the second tenant's repo is correct. Creating another repo that carries
a workspace tag already in use (same team and same tenant) does not create a new
workspace: both repos end up managing the same state, and deployments reference the wrong role
definition.
Before creating anything, search Azure DevOps for the repo that already owns your team's workspace for the tenant you need (corp or external). Search on the workspace tag rather than the repo name: names vary, some teams still have a single unsplit {Project}-business-roles repo, and the repo may live in a different project:
- Corp business roles repos, query:
-busrole-corp ext:tf - External business roles repos, query:
-busrole-external ext:tf
If a repo turns up for your team and tenant, add your Business Role there. If it still uses the deprecated okta-business-roles module or the old PascalCase YAML schema, follow the migration guide first. If the repo you find is a single unsplit {Project}-business-roles repo, not yet split into corp and external, the migration guide does not cover that case: coordinate with the Platform team before doing anything further, rather than following the migration guide or creating a new repo. Only create a new repo when the search returns nothing for that team and tenant combination.
Repository Structure¶
Business roles repositories typically follow a per-project naming convention:
| Type | Repository Pattern | Example |
|---|---|---|
| Corporate (Entra) | {Project}-okta-business-roles-corp |
SAIF-okta-business-roles-corp |
| External (Okta) | {Project}-okta-business-roles-external |
SAIF-okta-business-roles-external |
Team-Specific Repos, Org-Wide Deployment
Most teams manage their Business Roles in project-specific repos, but the naming pattern above is a convention, not a guarantee. The repo that owns your team and tenant workspace tag is authoritative, even when it sits in another project or uses a different name. Always trust the workspace tag search over the naming convention.
However the repo is named, the roles are deployed organization-wide. Any application across the organization can reference and use Business Roles created by any team.
This means:
- You can use Business Roles created by other teams
- Check if a suitable role already exists before creating a new one
- Coordinate with other teams to avoid duplicate roles
flowchart LR
subgraph repo1["Business Roles Repository"]
direction TB
file1["infra/okta/okta-business-roles.yml"]
config1["BusinessRoles:<br/>- Name: Premium Auditor<br/> RoleSets: ..."]
action1[/"CREATES the Business Role"/]
end
subgraph repo2["Your Application Repository"]
direction TB
file2["infra/auth/corp/config.yml"]
config2["business_roles:<br/>- name: Premium Auditor<br/> app_roles:<br/> - App.Read"]
action2[/"USES the Business Role"/]
end
repo2 -->|"references"| repo1
Common Error: Business Role Not Found
If you reference a Business Role in your app's auth config that doesn't exist in the business roles repository, you'll see:
Solution: Create the Business Role in the appropriate business roles repo first, then reference it in your app.Corporate Business Roles select users by the profile attributes Entra Connect syncs from on-premises AD.
File: infra/entra/business-roles.yml (in your corp business roles repo)
business_roles:
- name: "Claims Adjuster"
description: "Claims staff who process and adjust claims"
role_sets:
- division: Claims Division
job_titles: # jobTitle values from Entra ID user profiles
- Claims Adjuster I # matches users where jobTitle = "Claims Adjuster I"
- Claims Adjuster II # matches users where jobTitle = "Claims Adjuster II"
- Senior Claims Adjuster # matches users where jobTitle = "Senior Claims Adjuster"
manual_users: []
- name: "Premium Auditor"
description: "Staff who perform premium audits"
role_sets:
- division: Audit Division
job_titles:
- Premium Auditor
- Senior Premium Auditor
manual_users: []
- name: "HR Manager"
description: "Human Resources management staff"
role_sets:
- division: Human Resources Div
job_titles:
- HR Manager
- Senior HR Manager
manual_users:
- "jsmith" # Temporary access for testing
Configuration Fields:
| Field | Description |
|---|---|
name |
The Business Role name your app will reference |
description |
Human-readable description of the role's purpose |
role_sets |
User-attribute selectors; multiple entries are OR'd |
division |
Matches the synced division attribute, and must also be the display name of a real AD security group |
job_titles |
Matches the jobTitle attribute; free-form values, OR'd within the entry |
manual_users |
Individual usernames (mailNickname) to add, for testing/exceptions |
Membership is matched on attributes, not group membership
Both fields match user profile attributes synced from on-premises AD. Entra's memberOf
operator does not evaluate on-prem synced groups, so a user is selected by the value of
their division and jobTitle, never by what groups they belong to. Team names and AD
group names will silently match nobody.
The two fields are not validated the same way:
divisionis also looked up as an Entra ID security group display name during production plans. Divisions have real backing AD security groups, so a wrong value fails the plan rather than matching nothing.job_titlesare free-form profile values and are not validated. A wrong value plans and applies cleanly, then matches no users β which is the failure mode to watch for.
Confirm real values before deploying:
To see every title available in a division:
Non-production membership
In non-production these groups (bus-role-np.*) are created empty. role_sets and
manual_users apply to production only β Terraform will warn if you set manual_users
in a non-production workspace.
To grant yourself a corp role for testing, add it to Roles in
infra/np-role-assignment-corp/my-roles.yml in your personal test tools repo and run the
{project_id}-np-roles pipeline. That pipeline adds you directly to the bus-role-np.*
group. See Create Test Tools Repository.
External Business Roles use a simpler structure without division grouping.
File: infra/okta/business-roles.yml (in your external business roles repo)
business_roles:
- name: Injured Worker
description: Workers who have filed injury claims
roles:
- InjuredWorkerAccess
manual_users:
- TESTUSER001 # Test user for development
- name: Employer Representative
description: Employer contacts who manage claims for their organization
roles:
- EmployerRepAccess
- EmployerAdminAccess
manual_users: []
- name: Policy Holder
description: Policyholders who can view their policy information
roles:
- PolicyholderAccess
manual_users: []
- name: Medical Provider
description: Healthcare providers who submit treatment requests
roles:
- MedicalProviderAccess
manual_users: []
CompoundRoles (AND-Based Membership)¶
Use compound_roles when a user must belong to all listed groups simultaneously. This is useful for expressing complex access requirements without managing composite Okta groups out-of-band.
How the logic works:
rolesentries are OR'd β user needs membership in any of the listed groupscompound_rolesentries are AND'd within each entry β user must be in all groups in that entry- Multiple
compound_rolesentries are OR'd with each other and with flatroles
business_roles:
- name: "Policy Payroll Manager"
description: "Users who are both an NGP User AND a Policy Payroll Manager"
roles: []
compound_roles:
- roles:
- NGP User
- Policy Payroll Manager
manual_users: []
- name: "Senior Claims Admin"
description: "Super Admins OR users who hold both Claims and Admin roles"
roles:
- Super Admin
compound_roles:
- roles:
- Claims User
- Admin User
manual_users: []
Conceptual Okta expression examples:
The expressions below illustrate the logical result of the configuration shown above. They are conceptual examples, not guaranteed byte-for-byte output from the module β exact formatting, parentheses, and quoting may differ from the actual generated expression.
| Business Role | Example Okta Expression |
|---|---|
Policy Payroll Manager |
(isMemberOfGroupName("NGP User") AND isMemberOfGroupName("Policy Payroll Manager")) |
Senior Claims Admin |
isMemberOfGroupName("Super Admin") OR (isMemberOfGroupName("Claims User") AND isMemberOfGroupName("Admin User")) |
When to Use compound_roles
Use compound_roles when a single Okta group doesn't exist for the intersection of roles you need. If a group already represents the combined membership, use a flat roles entry instead.
Configuration Fields:
| Field | Description |
|---|---|
name |
The Business Role name used in app configuration |
description |
Human-readable description of the role's purpose |
roles |
Okta groups that grant this Business Role (OR logic β any group qualifies) |
compound_roles |
AND-based group requirements β user must be in all groups within each entry |
manual_users |
Individual users to add (use sparingly, for testing) |
manual_users for Testing
Use manual_users sparinglyβprimarily for test accounts or temporary exceptions. Production access should flow through proper security group membership.
π Using Business Roles in Your App¶
Once a Business Role exists, reference it in your application's auth configuration to grant users access.
File: infra/auth/corp/config.yml (in your app repo)
File: infra/auth/ext/user/business-role-app-role.yml (in your app repo)
Deployment Order Matters
- First: Deploy the business roles repo to create the Business Role
- Then: Deploy your app's auth config that references the Business Role
If you deploy your app first, the auth pipeline will fail because the Business Role doesn't exist yet.
π Business Role Management¶
Who Creates Business Roles?¶
Development teams create and manage Business Roles based on their needs:
- Identify organizational positions needing access
- Create the Business Role in the identity directory
- Follow the Division-Title naming convention
- Check if a suitable role already exists first
Team Responsibilities¶
| Action | Description |
|---|---|
| Create | New Business Roles for your application's needs |
| Configure | Map Business Roles to App Roles in config files |
| Document | Which Business Roles your app supports and why |
| Review | Check existing roles before creating new ones |
π Security Considerations¶
| Consideration | Guidance |
|---|---|
| Sensitivity | Business Roles represent org structureβprotect them |
| Audit trail | Log changes to Business Role assignments |
| Separation of duties | Role creators β role assigners |
| Regular reviews | Verify users still need their Business Roles |
| External scrutiny | Extra attention to external Business Roles |
π Related Documentation¶
- Configure User Permissions - Map Business Roles to app permissions
- Configure App Permissions - Set up API-to-API authorization
- Authorization Concepts - How authorization works in Forge