# 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 from existing security groups. Business Roles provide a logical name that applications can reference without knowing the underlying group structure.

**Key Concept**: Business Roles are created by mapping **existing security groups** to a friendly name. Users who belong to those groups automatically receive the Business Role.

**Examples**:

| Business Role Name | Maps From (Security Groups)                                    |
| ------------------ | -------------------------------------------------------------- |
| `Claims Adjuster`  | Claims Division → Claims Adjuster I, Claims Adjuster II, etc.  |
| `Finance Analyst`  | Finance Division → Financial Analyst, Senior Financial Analyst |
| `Premium Auditor`  | Audit Division → Premium Auditor, Senior Premium Auditor       |
| `HR Manager`       | HR Division → HR Manager, Senior HR Manager                    |

!!! info "Uniqueness Required"
    Business Roles must be **unique across the entire organization**. Each Business Role name can only exist once in the identity system.

!!! warning "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:

=== "Corporate (Entra ID)"

    | 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` |

=== "External (Okta)"

    | 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 |
| **user_impersonation** | -                        | Entra ID scope for user-context API calls         |
| **user-groups**        | -                        | Okta scope for user-context API calls             |

### 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.

### Repository Structure

Each Azure DevOps project has its own business roles repositories:

| 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` |

!!! info "Team-Specific Repos, Org-Wide Deployment"
    While each team manages their Business Roles in project-specific repos, 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

```mermaid
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
```

!!! danger "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 (Entra ID)"

    Corporate Business Roles aggregate users from existing Entra ID security groups within a division.

    **File:** `infra/entra/business-roles.yml` (in your corp business roles repo)

    ```yaml
    business_roles:
      - name: "Claims Adjuster"
        description: "Claims staff who process and adjust claims"
        role_sets:
          - division: Claims Division
            job_titles:                   # job title 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           # Security group
              - Senior Premium Auditor    # Security group
        manual_users: []

      - name: "HR Manager"
        description: "Human Resources management staff"
        role_sets:
          - division: Human Resources Div
            job_titles:
              - HR Manager                # Security group
              - Senior HR Manager         # Security group
        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`    | Security groups organized by division                               |
    | `division`     | The Entra ID organizational unit (must match exactly)               |
    | `job_titles`   | **Entra ID security groups** within that division                   |
    | `manual_users` | Individual usernames to add (use sparingly, for testing/exceptions) |

=== "External (Okta)"

    External Business Roles use a simpler structure without division grouping.

    **File:** `infra/okta/business-roles.yml` (in your external business roles repo)

    ```yaml
    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`

    ```yaml
    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"))` |

    !!! tip "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)                                  |

    !!! tip "`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.

=== "Corporate (Entra ID)"

    **File:** `infra/auth/corp/config.yml` (in your app repo)

    ```yaml
    # 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
    ```

=== "External (Okta)"

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

    ```yaml
    # 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
    ```

!!! warning "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          |

---

## 📚 Related Documentation

- [Configure User Permissions](user-permissions.md) - Map Business Roles to app permissions
- [Configure App Permissions](app-permissions.md) - Set up API-to-API authorization
- [Authorization Concepts](../../../reference/authorization.md) - How authorization works in Forge
