Manage Access with OIDC Group Claims and Teams
Automatically assign users to Mondoo teams based on identity provider group membership using OIDC group claims. An alternative to SCIM that requires no provisioning infrastructure.
Use OIDC group claims to automatically manage team membership in Mondoo. When users log in via SSO, Mondoo reads the group claims from their identity provider token and assigns them to Mondoo teams based on the mappings you define. This approach eliminates the need for SCIM provisioning infrastructure while giving you centralized, group-based access control.
How it works
- A user authenticates via your identity provider (Entra ID, Okta, or any OIDC provider).
- The IdP includes group claims in the JWT token.
- Mondoo matches those group IDs against your external group mappings.
- The user is automatically added to the corresponding Mondoo teams.
The key requirement is that your IdP must include group claims in the OIDC token. This is not always enabled by default.
Prerequisites
- A Mondoo Enterprise account with OIDC SSO configured. You only need the SSO section of the Entra ID or Okta setup guides (Entra ID SSO or Okta SSO). You do not need to configure SCIM provisioning.
- An API token with edit permission (for curl examples)
- Terraform >= 1.5 and the mondoohq/mondoo provider (for Terraform examples)
Step 1: Configure group claims in your IdP
Before Mondoo can read group membership from login tokens, you must configure your identity provider to include group claims. Mondoo reads the groups claim from the OIDC token to determine group membership.
Entra ID (Azure AD)
By default, Entra ID does not include group claims in tokens. You need to configure this in your app registration:
- In the Azure portal, go to your app registration.
- Under Token configuration, add a groups claim.
- Choose whether to emit group Object IDs or display names.
- For large organizations, consider filtering to specific groups rather than emitting all group memberships.
The external_id in Mondoo mappings should match the group Object ID (UUID) from Entra ID.
See Microsoft: Configure group claims for applications for detailed setup instructions.
Okta
Okta requires adding a custom groups claim to your authorization server:
- In the Okta admin console, go to Security > API > Authorization Servers.
- Select your authorization server and go to the Claims tab.
- Add a new claim named
groupswith value type Groups and a filter (for example, matches regex.*for all groups).
The external_id in Mondoo mappings should match the Okta group name or ID depending on your claim configuration.
See Okta: Customize tokens with a groups claim for detailed setup instructions.
Step 2: Create Mondoo teams
Create Mondoo teams that correspond to access levels you want to grant. Each team can be scoped to an organization or a space.
When creating teams, set the team id explicitly. Auto-generated IDs are not human-readable and make management harder. IDs must be 4 to 64 characters: lowercase letters, digits, dashes, and underscores. No leading dashes.
With Terraform
resource "mondoo_team" "security_viewers" {
id = "security-viewers"
name = "Security Viewers"
scope_mrn = mondoo_organization.production.mrn
}With curl
curl -X POST https://us.api.mondoo.com/query \
-H "Authorization: Bearer $MONDOO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($input: CreateTeamInput!) { createTeam(input: $input) { mrn name } }",
"variables": {
"input": {
"id": "security-viewers",
"name": "Security Viewers",
"scopeMrn": "//captain.api.mondoo.app/organizations/YOUR-ORG-ID"
}
}
}'Replace YOUR-ORG-ID with your Mondoo organization ID. To scope the team to a space instead, use //captain.api.mondoo.app/spaces/YOUR-SPACE-ID.
The API endpoint varies by region. Use https://us.api.mondoo.com for the US region or https://eu.api.mondoo.com for the EU region.
Step 3: Assign roles to teams
Grant each team the appropriate roles on the resources they need access to.
Available roles
| Role MRN | Description |
|---|---|
//iam.api.mondoo.app/roles/viewer | Read-only access |
//iam.api.mondoo.app/roles/editor | Read-write access |
//iam.api.mondoo.app/roles/owner | Full control including IAM |
//iam.api.mondoo.app/roles/agent | Asset scanning agent |
//iam.api.mondoo.app/roles/platform-admin | Platform-level administration |
//iam.api.mondoo.app/roles/policy-manager | Manage policies |
//iam.api.mondoo.app/roles/policy-editor | Edit policies |
//iam.api.mondoo.app/roles/exception-reviewer | Review security exceptions |
//iam.api.mondoo.app/roles/exceptions-requester | Request security exceptions |
//iam.api.mondoo.app/roles/integrations-manager | Manage integrations |
//iam.api.mondoo.app/roles/ticket-manager | Manage tickets |
//iam.api.mondoo.app/roles/ticket-creator | Create tickets |
//iam.api.mondoo.app/roles/query-pack-manager | Manage query packs |
//iam.api.mondoo.app/roles/query-pack-editor | Edit query packs |
//iam.api.mondoo.app/roles/sla-manager | Manage SLA settings |
Grant organization-wide access
With Terraform
resource "mondoo_iam_binding" "security_viewers" {
identity_mrn = mondoo_team.security_viewers.mrn
resource_mrn = mondoo_organization.production.mrn
roles = [
"//iam.api.mondoo.app/roles/viewer",
]
}With curl
curl -X POST https://us.api.mondoo.com/query \
-H "Authorization: Bearer $MONDOO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($input: SetRolesInput!) { setRoles(input: $input) { identity_mrn } }",
"variables": {
"input": {
"scopeMrn": "//captain.api.mondoo.app/organizations/YOUR-ORG-ID",
"identity": "//captain.api.mondoo.app/organizations/YOUR-ORG-ID/teams/security-viewers",
"roles": [
"//iam.api.mondoo.app/roles/viewer"
]
}
}
}'Grant space-scoped access
To restrict a team's access to a single space:
With Terraform
resource "mondoo_iam_binding" "space_editors" {
identity_mrn = mondoo_team.space_editors.mrn
resource_mrn = mondoo_space.infrastructure.mrn
roles = [
"//iam.api.mondoo.app/roles/editor",
]
}With curl
curl -X POST https://us.api.mondoo.com/query \
-H "Authorization: Bearer $MONDOO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($input: SetRolesInput!) { setRoles(input: $input) { identity_mrn } }",
"variables": {
"input": {
"scopeMrn": "//captain.api.mondoo.app/spaces/YOUR-SPACE-ID",
"identity": "//captain.api.mondoo.app/organizations/YOUR-ORG-ID/teams/space-editors",
"roles": [
"//iam.api.mondoo.app/roles/editor"
]
}
}
}'Grant workspace-scoped access
To restrict a team's access to a specific workspace within a space:
With Terraform
resource "mondoo_iam_binding" "workspace_viewers" {
identity_mrn = mondoo_team.workspace_viewers.mrn
resource_mrn = mondoo_workspace.virtual_machines.mrn
roles = [
"//iam.api.mondoo.app/roles/viewer",
"//iam.api.mondoo.app/roles/exceptions-requester",
]
}Step 4: Map IdP groups to Mondoo teams
Link each identity provider group to its corresponding Mondoo team. When users log in, Mondoo checks their group claims and assigns team membership automatically.
With Terraform
resource "mondoo_team_external_group_mapping" "security_viewers" {
team_mrn = mondoo_team.security_viewers.mrn
external_id = "a1b2c3d4-0000-0000-0000-000000000000" # Entra ID group Object ID
}With curl
curl -X POST https://us.api.mondoo.com/query \
-H "Authorization: Bearer $MONDOO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($input: AddTeamExternalGroupMappingInput!) { addTeamExternalGroupMapping(input: $input) { mrn externalId } }",
"variables": {
"input": {
"teamMrn": "//captain.api.mondoo.app/organizations/YOUR-ORG-ID/teams/security-viewers",
"externalId": "a1b2c3d4-0000-0000-0000-000000000000"
}
}
}'For externalId, use the group Object ID (UUID) from Entra ID or the group name/ID from Okta, depending on how you configured your group claims.
Scaffold mappings before group IDs are ready
If you are setting up Terraform resources before the IdP group IDs are available, you can use conditional creation:
locals {
# Populate when IdP groups are ready, e.g.:
# "viewers" = "a1b2c3d4-0000-0000-0000-000000000000"
external_group_ids = {}
}
resource "mondoo_team_external_group_mapping" "security_viewers" {
count = contains(keys(local.external_group_ids), "viewers") ? 1 : 0
team_mrn = mondoo_team.security_viewers.mrn
external_id = lookup(local.external_group_ids, "viewers", "")
}Use lookup() with a default value instead of direct indexing. Terraform evaluates the expression even when count = 0, so direct indexing on an empty map causes an error.