Okta Integration

How it Works

Access Manager uses the Okta API to read data about existing Okta Applications, Groups, and Users and attach an existing Okta User with an Okta Application or Okta Group that grants them access to authenticate with the respective application using Okta SSO.

Access Manager focuses on managing Okta User associations with Okta Applications and/or Okta Groups. Due to multi-dimensional design complexities, we do not manage Okta Application Group associations, however we do use the API to get a read only list of Okta Applications that are associated with each Okta Group that Access Manager manages.

Integration with Access Manager

Access Manager uses the same generic architecture terminology for each provider that we integrate with to allow us to reuse the same controllers, database migrations, models, services, and views. For documentation purposes, we refer to the combination of these reusable components as the Saas namespace architecture.

Data Models

Access Manager Actions Okta
AuthProvider Read Only Okta Application OpenID Connect Client (SSO)
AuthUser Read Only Okta User via OIDC SSO
SaasProvider API Endpoint Definitions Okta (Vendor)
SaasInstance Read Only Okta Organization (Domain) and API Credentials
SaasEntity Read Only Okta Application
N/A N/A Okta Application Group
SaasEntityUser Read Write Okta Application User
SaasEntity Read Write Okta Group
SaasEntityUser Read Write Okta Group User
SaasUser Read Only Okta User

Provisioning Approaches

You can use Access Manager for two provisioning method approaches:

  1. Okta Application Provisioning Approach - You can add/remove Okta Users from an Okta Application.
  2. Okta Group Provisioning Approach - You can add/remove Okta Users from an Okta Group.
  3. Hybrid Approach

You can choose whether to use one or both of these approaches, however there are considerations for each to keep in mind.

Okta Application Provisioning Approach

With an Okta Application provisioning approach, you are managing least privilege for each user based on their metadata that provides granular role based access control and approvals. In essence, you are using Access Manager to control specific access to each application.

You will need to add a new or existing Access Manager Approval Policy to each Okta application to define how the Approval Flow will work for each user.

Benefits
  • This improves the user experience for the Access Manager catalog since users can click on specific applications to request access to.
  • This approach is advantageous for sensitive least privilege systems that you need tighter control of.
  • You have explicit control of which Okta Users have access to each Okta Application rather than assuming that every member of a department or a job role should have access.
  • This increases clarity for approvers in Approval Flows of which application a user is getting access to.
Considerations
  • This approach may be unnecessarily complicated for Okta Applications that you consider to be part of your baseline entitlements (applications that everyone should have access to without approval). It can be done if you need granular control of all of your applications, however an Okta Group provisioning approach may make more sense for ease-of-use if you do not need granular control of some of your Okta Applications.
  • You will need to add a new or existing Approval Policy to each Okta Application in Access Manager. This specifies which users can get access and defines how the Approval Flow works for each user.
  • It takes a lot of time to determine which Applications should have which Approval Policies, and the different Approval Policies for each Application for different departments or job roles that allows easier access for pre-approved groups of users.
  • This reduces or eliminates the use of Okta Groups and dynamic rules for this Okta Application since each user is assigned to an Application rather than granting access to a group that is pre-configured with access to one or more Okta applications.
  • This adds users directly to Okta Applications that create an exhaustive list of users, however can be difficult to visualize categories/groups of users at a glance when using the Okta UI or API directly.

Okta Group Provisioning Approach

With an Okta Group provisioning approach, you are managing access to Okta Groups, which are then used to grant groups of users to Okta Applications.

This approach works well for applications that you grant access to a large number of users based on "group" metadata and doesn't require granular control for specific individuals.

Benefits
  • You can grant access to an Okta Group that is already associated with one or more Okta Applications to provide bulk access to multiple Okta Applications with a single Approval Flow.
  • You can use the same benefits that Okta Groups provide while adding authorization automation with Approval Policies and Approval Flows.
  • You have flexibility to determine whether to use Okta dynamic rules for adding users to Okta Groups, since any changes performed in Okta will be automatically synced to Access Manager since full Okta User and Okta Group directory is cached in the Access Manager.
  • You can use existing Okta Application and Okta Group configuration in your Okta Instance.
  • You can separate the implementation of Okta Applications and Groups from Okta User management, which allows you to implement Access Manager with less migration or "redo" work.
  • This approach is relatively easy to implement quickly and start realizing benefits.
Considerations
  • This approach is not ideal for hardened or sensitive data applications that should have as few users as possible.
  • This approach is not ideal for Okta applications that have strict least privilege policies.
  • Less granular access allows you to have fewer groups with a larger number of users.
  • This works well when you have an Okta Group for each department.
  • This can be overwhelming when you a lot of Okta Groups, particularly when you have a group for each job family/title. You should use the Application approach with Access Manager Approval Policies for this use case.
  • In the current version of Access Manager, the user experience of the catalog will not be as easy to navigate to determine "which groups grant me access to this application".

Hybrid Approach

Based on the benefits and considerations for the Application and Group approach, you can use a hybrid approach with the following getting started design suggestions:

  1. Choose the Group approach for any applications that a large number of team members should have access to based on common metadata. This is useful for "all users" and "all users in a department" use cases.
  2. Choose the Application approach for any least privilege applications. This is useful for financial, infrastructure, report tools, and other applications that your organizations considers to be sensitive.
  3. Any applications that are in-scope for audit and compliance review should use the Application approach.
  4. Be careful not to overuse the Group approach and end up with hundreds of groups that are difficult to manage and distinguish the variations from each other. It is better to use Access Manager groups for more granular group permissions since user access to these groups includes Approval Policy support and are included in Access Manager audit reporting.

Architecture

Okta Providers

The configuration for the AuthProvider and SaasProvider are not dependent on each other and you can use one without the other. If both are configured, an AuthProvider successful user authentication attempt can be configured to trigger a real time sync for a user's Okta profile metadata and an AuthUser's metadata can be displayed based on the relationship with the SaasUser based on the Okta ID.

The Okta SaasProvider has the metadata about the different data models, methods, and services that Access Manager uses for administratively managing your Okta organization users, groups, and applications using the API integration. This is built into the Access Manager source code and does not need to be customized. You can create an Okta Instance for each organization that you want to manage with Access Manager.

The Okta AuthProvider has the OpenID Connect (OIDC) client configuration for users to sign in to the Access Manager UI using Okta Single-Sign On (SSO). You do not need to generate an administrative API token or service account to use Okta SSO. See the Single Sign On documentation to learn more about configuring SSO for Access Manager users.

Okta Instances

Access Manager allows you to manage the users, groups, and application member for one or more Okta organization (sub)domain(s).

When you add a SaasInstance for your Okta organization, you'll need your Okta domain (ex. example.okta, example.oktapreview.com, dev-12345678.okta.com) and an API token that you generate in the Okta Admin UI.

See the API Tokens section to learn more about how to create an API token and security best practices.

Okta Users

Auth Provider

You can configure Access Manager to use Okta SSO by configuring an AuthProvider which contains the OpenID Connect (OIDC) client configuration.

User Identity

Each time that a user authenticates with Okta SSO, Access Manager checks if the user exists in the auth_users table and creates a new AuthUser model if it does not exist. The full_name, email, and okta_id fields are stored in the auth_users table and used as part of the authentication session.

See the Single Sign On documentation to learn more about configuring SSO for Access Manager users.

User Permissions

Access Manager permissions are managed by AuthRole permissions array that define which controller routes a user can access. This provides granular access to each database model's index, show, create, store, edit, update, delete endpoints. Each AuthRole has a many-to-many relationship with one or more AuthGroup(s), and each AuthGroup is associated with one or more AuthUser(s).

When a user authenticates with Okta, the user metadata is returned that aligns with the SCIM protocol schema.

You can use any of the user metadata fields returned in the Okta response to perform string matching with AuthProviderGroup rules to automatically add users to the specified AuthGroup. These metadata fields only exist in short term memory and are not stored in the database to avoid data retention security risks. A log entry is created each time that an AuthGroupUser is created based on AuthProviderGroup metadata.

Saas Provider

When your Okta Instance is created, the list of Okta Users in the Okta Instance is imported as a SaasUser.

The Okta Users and their profile metadata is routinely synced with a background job. The interval (default 24 hours) is customizable in config/am-provider-okta.php. An Access Manager administrator can also perform an on-demand sync using the Admin UI or saas-instance:sync {instance_short_id} CLI command.

Although the Okta API supports creating Okta Users, the current version of Access Manager only uses the Okta Users in a read-only capacity to get your Okta Organization's existing directory of human user accounts that is either configured within Okta or uses an Okta Profile Source (ex. Active Directory, Human Resources Information System, etc.) to create your Okta Users.

Cross-Functional Relationship

The only users in the auth_users table are those that have authenticated with Access Manager's UI. The full directory of users is stored in the saas_users table. This design keeps a separation of duties for authentication and application user management with the Okta API.

The AuthUser and SaasUser model in Access Manager have a one-to-one relationship to automatically detect if the Okta ID exists in both the auth_users and saas_users database table. This allows Access Manager to display the user's profile metadata but only store it in one place, and can also render more metadata about the user from the SaasUser relationship including their job title, manager, department, and other metadata fields that are not related to authentication.

Okta Applications

Access Manager provides a read-only view of all Okta applications by importing the metadata for each application as a SaasEntity.

See Okta Application Users to learn more about the relationship of Okta Applications (SaasEntity) and Okta Users (SaasUsers).

See Okta Application Groups to learn more about the relationship of Okta Applications and Okta Groups. Access Manager can create and manage Okta Groups and Okta Group Users, however Access Manager only has read only access to Okta Application Groups. In other words, Access Manager manages association of a user with a group, but does not manage group associations with applications.

Okta Application Users

Okta Applications (SaasEntity) and Okta Users (SaasUser) have a many-to-many relationship that is created as a SaasEntityUser.

When you import an Okta Instance (SaasInstance) for the first time, all of the existing Okta Applications, Okta Users, and the Application Users will be imported and created in the Access Manager database.

When you sync an Okta Instance after it has been created, all of the data returned in the API response is synced with the existing state of the Access Manager database to check for differences and perform an extract-transform-load (ETL) process to update existing records, add records that exist in Okta but not Access Manager, and delete users that do not exist in Okta and do exist in Access Manager.

As users get approved to access an application, a new SaasEntityUser record is created and the Okta API is used for a real-time creation of the relationship in your Okta Instance.

When a user's access expires (see SaasEntityUser expires_at field) or is removed (deprovisioning and/or offboarding) in Access Manager, the Okta API is used for real-time deletion of the relationship in your Okta Instance.

Okta Application Groups

Access Manager does not manage the association of Okta Groups to Okta Applications.

Due to design complexities, it was decided that AccessManager would focus on user provisioning for Okta Applications and Okta Groups. This design decision reduced the integration and multi-dimensional complexity by more than 50% while still retaining most of the benefits.

You can still use the Okta UI, API, or configuration management tools (outside of Access Manager) to add Okta Groups to Okta Applications, and use Access Manager for managing which Okta Users belong to each Okta Group.

Since Access Manager manages Okta Groups, the metadata about which Okta Applications are associated with each Okta Group are displayed in the UI using the Application ID to show the applications associated with the group.

Okta Groups

Access Manager allows you to create, modify, and delete Okta Groups (SaasEntity) and manage users associated with Okta Groups using a SaasEntityUser.

Okta supports groups that are managed by Okta, and importing groups managed by a 3rd party application (ex. Google Workspace, HRIS, etc.).

Due to API limitations, Okta cannot manage the members of groups managed by 3rd party applications. Access Manager ignores 3rd party application managed groups and does not store them in the database.

See Okta Application Groups to learn more about the relationship of Okta Applications and Okta Groups. Access Manager can create and manage Okta Groups and Okta Group Users, however Access Manager only has read only access to Okta Application Groups. In other words, Access Manager manages association of a user with a group, but does not manage group associations with applications.

Workflows

Importing Okta Instances

TODO

Managing Users

TODO

Managing Applications

TODO

Managing Groups

TODO

Managing Okta Application Users

TODO

Managing Okta Group Users

TODO

API Integration

The glamstack/okta-sdk Composer package is used to connect to the Okta REST API.

API Tokens

The domain and API token credentials for each of your Okta SaasInstance(s) are stored in the saas_instances database table and is encrypted at rest using bcrypt. The credentials are accessed by the OktaBaseService when instantiating the Okta SDK. The API credentials are not stored in any configuration files on the application server file system or in the source code.

When you create an API token in Okta, the permissions are inherited from and match the user that created the API token.

If you create an API token from your Super Administrator or another elevated privilege level user account, your Access Manager API token will be overpermissive and break the least privilege principle. You will also see all log events for Access Manager will appear to be performed by your human user account since the API token is associated with your user account.

The best practice is to create a new Okta user account for Access Manager that will function as a service account, although keep in mind that the Okta documentation doesn't refer to it as a service account.

TODO Define list of permissions, roles, or custom roles for Access Manager user account.

Data Retention

When an API call is performed, all of the data fields are returned with API calls and are temporarily stored in memory for processing. For data security reasons, Access Manager only stores the data necessary for relationship mapping and audit use cases.

The Access Manager database tables have (string) api_record_id and (json) api_meta_data columns that are used for storing any of the data model fields that Access Manager retains in the database. For commonly used summary information, we also have additional database fields (ex. name, slug, description) that data model fields are mapped to as needed. See Data Transfer Objects to learn more about all of the Okta data model fields and the default data retention configuration.

For user interface (UI) use cases where additional metadata is needed, an on-demand API call is performed for the specific resource (ex. OktaApp, OktaGroup, OktaUser) and will be cached in that user's session for a short duration. The duration of the cache is specified in config/cache.php or in the controller method for the respective page.

This approach ensures that if a data breach were to occur, the Personal Identifyable Information (PII) is limited to a user's first and last name and organization chart directory metadata (job title, job family, department, manager, work email address).

You can manage the data retention policies and redact specific fields from the database globally in the config/am-provider-okta.php configuration file.

Data Transfer Objects and Models

OktaApp Data Model

DTO Model DTO Field Database Table Database Column Database JSON Key
OktaApp id saas_entities api_record_id N/A
OktaApp id saas_entities api_meta_data id
OktaApp label saas_entities name N/A
OktaApp label saas_entities slug N/A
OktaApp label saas_entities api_meta_data label
OktaApp name saas_entities description N/A
OktaApp name saas_entities api_meta_data name
OktaApp signOnMode saas_entities api_meta_data signOnMode
OktaApp status saas_entities api_meta_data status
OktaApp timestamps.created saas_entities provisioned_at N/A
OktaApp timestamps.created saas_entities api_meta_data timestamps.created
OktaApp timestamps.lastUpdated saas_entities api_meta_data timestamped.lastUpdated

OktaGroup Data Model

DTO Model DTO Field Database Table Database Column Database JSON Key
OktaGroup id saas_entities api_record_id
OktaGroup id saas_entities api_meta_data id
OktaGroup group_type.name saas_entities api_meta_data group_type.name
OktaGroup group_type.source_id saas_entities api_meta_data group_type.source_id
OktaGroup group_type.type saas_entities api_meta_data group_type.type
OktaGroup default_profile.description saas_entities api_meta_data default_profile.description
OktaGroup default_profile.name saas_entities api_meta_data default_profile.name
OktaGroup custom_profile.{field} saas_entities api_meta_data custom_profile.{field}
OktaGroup timestamps.created saas_entities provisioned_at
OktaGroup timestamps.created saas_entities api_meta_data timestamps.created
OktaGroup timestamps.lastMembershipUpdated saas_entities api_meta_data timestamps.lastMembershipUpdated
OktaGroup timestamps.lastUpdated saas_entities api_meta_data timestamps.lastUpdated

OktaUser Data Model

DTO Model DTO Field Database Table Database Column Database JSON Key
OktaUser id saas_users api_record_id
OktaUser id saas_users api_meta_data id
OktaUser user_type.id saas_users api_meta_data user_type.id
OktaUser user_type.displayName saas_users api_meta_data user_type.displayName
OktaUser user_type.name saas_users api_meta_data user_type.name
OktaUser status saas_users api_meta_data status
OktaUser default_profile.city N/A
OktaUser default_profile.costCenter N/A
OktaUser default_profile.countryCode N/A
OktaUser default_profile.department saas_users api_meta_data default_profile.department
OktaUser default_profile.displayName saas_users api_meta_data default_profile.displayName
OktaUser default_profile.division saas_users api_meta_data default_profile.division
OktaUser default_profile.email saas_users api_meta_data default_profile.email
OktaUser default_profile.employeeNumber saas_users api_meta_data default_profile.employeeNumber
OktaUser default_profile.firstName N/A
OktaUser default_profile.honorificPrefix N/A
OktaUser default_profile.honorificSuffix N/A
OktaUser default_profile.lastName N/A
OktaUser default_profile.locale N/A
OktaUser default_profile.login saas_users api_meta_data default_profile.login
OktaUser default_profile.manager saas_users api_meta_data default_profile.manager
OktaUser default_profile.managerId saas_users api_meta_data default_profile.managerId
OktaUser default_profile.middleName N/A
OktaUser default_profile.mobilePhone N/A
OktaUser default_profile.nickName N/A
OktaUser default_profile.organization N/A
OktaUser default_profile.postalAddress N/A
OktaUser default_profile.preferredLanguage N/A
OktaUser default_profile.primaryPhone N/A
OktaUser default_profile.profileUrl N/A
OktaUser default_profile.secondEmail N/A
OktaUser default_profile.state N/A
OktaUser default_profile.streetAddress N/A
OktaUser default_profile.timezone N/A
OktaUser default_profile.title saas_users api_meta_data default_profile.title
OktaUser default_profile.userType saas_users api_meta_data default_profile.userType
OktaUser default_profile.zipCode N/A
OktaUser custom_profile.{field_name} N/A
OktaUser timestamps.activated saas_users api_meta_data timestamps.activated
OktaUser timestamps.created saas_users provisioned_at
OktaUser timestamps.created saas_users api_meta_data timestamps.created
OktaUser timestamps.lastLogin saas_users api_meta_data timestamps.lastLogin
OktaUser timestamps.lastUpdated saas_users api_meta_data timestamps.lastUpdated
OktaUser timestamps.passwordChanged saas_users api_meta_data timestamps.passwordChanged
OktaUser timestamps.statusChanged saas_users api_meta_data timestamps.statusChanged

OktaAppUser Data Model

DTO Model DTO Field Database Table Database Column Database JSON Key
OktaAppUser id saas_entities_users api_record_id
OktaAppUser id saas_entities_users api_meta_data id
OktaAppUser externalId saas_entities_users api_meta_data externalId
OktaAppUser scope saas_entities_users api_meta_data scope
OktaAppUser credentials.userName saas_entities_users api_meta_data credentials.userName
OktaAppUser credentials.{field} saas_entities_users api_meta_data credentials.{field}
OktaAppUser profile.{field} saas_entities_users api_meta_data profile.{field}
OktaAppUser status saas_entities_users api_meta_data status
OktaAppUser timestamps.created saas_entities_users provisioned_at
OktaAppUser timestamps.created saas_entities_users api_meta_data timestamps.created
OktaAppUser timestamps.lastUpdated saas_entities_users api_meta_data timestamps.lastUpdated
OktaAppUser timestamps.statusChanged saas_entities_users api_meta_data timestamps.statusChanged
OktaAppUser timestamps.passwordChanged saas_entities_users api_meta_data timestamps.passwordChanged
OktaAppUser timestamps.lastSync saas_entities_users api_meta_data timestamps.lastSync

OktaGroupUser Data Model

DTO Model DTO Field Database Table Database Column Database JSON Key
OktaGroupUser id saas_entities_users api_record_id
OktaGroupUser id saas_entities_users api_meta_data id
OktaGroupUser externalId saas_entities_users api_meta_data externalId
OktaGroupUser credentials.userName saas_entities_users api_meta_data credentials.userName
OktaGroupUser credentials.{field} saas_entities_users api_meta_data credentials.{field}
OktaGroupuser profile.{field} saas_entities_users api_meta_data profile.{field}
OktaGroupUser scope saas_entities_users api_meta_data scope
OktaGroupUser timestamps.created saas_entities_users provisioned_at
OktaGroupUser timestamps.created saas_entities_users api_meta_data timestamps.created
OktaGroupUser timestamps.lastUpdated saas_entities_users api_meta_data timestamps.lastUpdated
OktaGroupUser timestamps.statusChanged saas_entities_users api_meta_data timestamps.statusChanged
OktaGroupUser timestamps.passwordChanged saas_entities_users api_meta_data timestamps.passwordChanged
OktaGroupUser timestamps.lastSync saas_entities_users api_meta_data timestamps.lastSync

Security Best Practices

Administrator Self-Approval

In a development environment, an administrator needs to be able to make every kind of change to configure and test the software.

In a production environment, it is important to have separation of responsibilities and ensure that an administrator can't make unauthorized changes. This is usually a requirement for audit and compliance reasons.

Hardening Solution: The APP_ENV variable in .env is used to determine whether developer functionality is available. By default, this is set to production. This will ensure that an administrative user cannot make changes to their own profile. If this is set to any other value (ex. local, test), then an administrative user can make changes to their own profile. This variable can be changed by an administrator to circumvent this, however any changes to a user's own profile performed while the APP_ENV is not set to production will have a critical log entry created which will create an alert in your preferred bug reporting tool (ex. Bugsnag or Sentry).

Auth Provider OpenID Connect

TODO

Unexpected Okta User Profile Metadata Changes

The title and department fields contains metadata for the user that is often used for string condition matching with AuthProviderGroup dynamic rule for creating an AuthGroupUser in AccessManager.

In addition to using the title and department values, you can use other metadata fields in an Okta user profile for additional AuthProviderGroup dynamic rules.

If one of these values is changed in Okta or in an Okta Profile source upstream (ex. Human Resources Information System or supplemental directory), then the user will be automatically be granted access to an AuthGroup if an [AuthProviderGroup] rule matches, which may allow automatic approval for access to SaasProviders with different and/or elevated access.

Hardening Solution: It is important to have change management policies and protections in place for changes to the these metadata fields for each user in Okta and Profile Source application(s).

Hardening Solution: You can set sync.metadata.change-mgmt.approval = true in config/am-provider-okta.php which requires an Access Manager user with the TODO permission to approve the change before it is applied to the SaasUser profile. The tradeoff is that this will reduce the automation for job role changes and require administrative manual approvals for all metadata changes.

Hardening Solution: You can avoid creating any Approval Policies for some or all systems that provide automatic approval based solely on user meta data (ex. title or department) without human approval. The tradeoff is that there will be significantly more access request approval steps for pre-approved/designated role-based access.

Manager Changes

The manager and managerId fields are used for organizational chart hierarchy and Approval Policies in Access Manager.

If one of these values is changed in Okta or in an Okta Profile source upstream (ex. Human Resources Information System), then any Approval Policies with a manager approval will be sent to the new manager.

This is expected behavior as teams reorganize or users change to a different job family. The update to a Directory User's profile metadata will take place after one of the following events takes place:

  • The AuthUser authenticates to Access Manager with Okta and the DirectoryUser metadata is automatically synced. This can be disabled by setting sync.sso.enabled = false in config/am-provider-okta.php.
  • The background job for routinely syncing the Access Manager Directory Users has completed. The interval (default 24 hours) is customizable in config/am-provider-okta.php.
  • An Access Manager administrator performs a manual Directory Sync using the Admin UI or am-provider-okta:sync {instance_short_id} CLI command.

After the value is reflected in the Access Manager Directory User profile, this manager will be used for all Approval Flows that are created after the value is changed. Any existing Approval Flows will continue to use the old manager. You can simply cancel the exisitng Approval Flow and create a new Approval Flow to have approval performed by the new manager.

Since Approval Flows are intended to be one or more simple approved transactions, Access Manager does not support modifying the approver on an existing Approval Flow since this creates an Approval Policy exception and introduces unnecessary complexity.

However, if this value is changed by a user in Okta or an Okta Profile source system to an unexpected value, this may allow users to bypass the "proper" approval process. The following scenarios should be considered as part of your organization's threat modeling and hardening policies:

  • An administrative user has a friendship or helpful support relationship with a user, and that user needs to get access to a system that requires manager approval and they don't want to notify their manager of the request. The administrative user can change the user's manager to the administrative user's ID or another user that can approve an ApprovalFlow. This may be performed for innocent reasons (ex. manager is on vacation and delegated approvals are handled by a senior leadership team member that the user doesn't want to bother) or for malicious reasons (ex. to get access to a backend system).
  • An administrative user needs access to a system and doesn't want to wait for manager approval.
  • The Okta Profile source system may have a drag and drop organization chart UI that a user accidentally can be moved to a different manager.
  • Your Okta Profile source uses an organization chart integration that allows manager changes using a self service request without additional oversight approvals.

Hardening Solution: It is important to have change management policies and protections in place for changes to the these metadata fields for each user in Okta and Profile Source application(s).

Hardening Solution: You can enable metadata change approval in config/am-provider-okta.php which requires an Access Manager user with the TODO permission to approve the change before it is applied to the SaasUser profile. The tradeoff is that this will reduce the automation for job role changes and require administrative manual approvals for all metadata changes.

Hardening Solution: You can avoid creating any Approval Policies for some or all systems that provide automatic approval based solely on user meta data (ex. title or department) without human approval. The tradeoff is that there will be significantly more access request approval steps for pre-approved/designated role-based access.