Skip to content

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:

  1. Assignment: User is assigned Business Roles based on organizational position
  2. Mapping: Applications define which Business Roles can access them
  3. Permissions: Each Business Role is granted specific App Roles (permissions)
  4. 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

  1. User is assigned Claims Adjuster Business Role
  2. Your app has Claims Adjuster mapped to [App.Read, App.Write]
  3. User automatically gets those permissions
  4. No manual access grant needed

Scenario 2: External User Access

  1. Injured worker is assigned Injured Worker Business Role (external)
  2. Your app maps Injured Worker to [App.Read]
  3. Injured worker gets read-only access to their claim
  4. Clearly separated from corporate users

Scenario 3: Department Change

  1. User moves from Claims to Finance
  2. Business Role changes: Claims Adjuster β†’ Finance Analyst
  3. User automatically loses Claims permissions, gains Finance permissions
  4. 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:

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:

Error: No group found matching specified filter
(displayName eq 'bus-role-np.developer' and securityEnabled eq true)
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:

  • division is 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_titles are 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:

Get-ADUser -Identity jsmith -Properties Title,Division |
    Select-Object Name, Title, Division

To see every title available in a division:

Get-ADUser -Filter "Division -eq 'Claims Division'" -Properties Title |
    Group-Object Title | Sort-Object Count -Descending | Select-Object Count, Name

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:

  • roles entries are OR'd β€” user needs membership in any of the listed groups
  • compound_roles entries are AND'd within each entry β€” user must be in all groups in that entry
  • Multiple compound_roles entries are OR'd with each other and with flat roles
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)

# Map existing Business Roles to your app's permissions
business_roles:
  - name: Premium Auditor      # Must exist in business roles repo
    app_roles:
      - App.Read
      - App.Write
  - name: Claims Adjuster      # Must exist in business roles repo
    app_roles:
      - App.Read

File: infra/auth/ext/user/business-role-app-role.yml (in your app repo)

# Map existing Business Roles to your app's permissions
authorized_business_roles:
  - name: Injured Worker       # Must exist in business roles repo
    app_roles:
      - App.Read
  - name: Employer Representative
    app_roles:
      - App.Read
      - App.Write

Deployment Order Matters

  1. First: Deploy the business roles repo to create the Business Role
  2. 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