Skip to content

Role Mappings

Configure automatic role assignment based on identity provider groups.

Role mappings automatically assign Mantis roles to users based on their IdP group membership, enabling centralized access control management.

ModeDescriptionUse Case
additiveOnly add roles, never removeDefault, safe for mixed environments
fullSync exactly to IdP groupsFull IdP control of roles
noneDon’t sync roles at allManual role management only
CREATE TABLE identity_provider_role_mappings (
id UUID PRIMARY KEY,
provider_id UUID NOT NULL REFERENCES identity_providers(id) ON DELETE CASCADE,
external_group TEXT NOT NULL,
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
priority INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE (provider_id, external_group, role_id)
);
  1. Navigate to AdminIdentity Providers
  2. Select the provider
  3. Click Role Mappings tab
  4. Click Add Mapping
  5. Enter:
    • External Group: Group name from IdP (exact match)
    • Role: Mantis role to assign
    • Priority: Higher priority mappings processed first
-- Map IdP group "Mantis-Admins" to admin role
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id, priority)
SELECT
(SELECT id FROM identity_providers WHERE name = 'Okta'),
'Mantis-Admins',
(SELECT id FROM roles WHERE name = 'admin'),
100;
-- Map IdP group "Mantis-Operators" to operator role
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id, priority)
SELECT
(SELECT id FROM identity_providers WHERE name = 'Okta'),
'Mantis-Operators',
(SELECT id FROM roles WHERE name = 'operator'),
50;
-- Map IdP group "Everyone" to viewer role
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id, priority)
SELECT
(SELECT id FROM identity_providers WHERE name = 'Okta'),
'Everyone',
(SELECT id FROM roles WHERE name = 'viewer'),
10;

role_sync_mode is not yet exposed through the REST API. Set it directly in the database:

UPDATE identity_providers SET role_sync_mode = 'full' WHERE id = '$IDP_ID';

Valid values are additive (default), full, and none.

  • Roles from IdP groups are added
  • Existing roles are preserved
  • Roles are never removed
  • Roles controlled by this provider’s mappings are synced to current IdP group membership
  • Roles whose corresponding IdP group the user no longer belongs to are removed
  • Roles not managed by any mapping for this provider are preserved
  • System roles (is_system=true) are never removed
  • Role mappings are ignored
  • Roles must be assigned manually
  • Default role (if configured) is still assigned to new users

Higher priority mappings are processed first:

SELECT external_group, role_id
FROM identity_provider_role_mappings
WHERE provider_id = $provider_id
ORDER BY priority DESC;
External GroupRolePriority
Mantis-SuperAdminsadmin100
Mantis-Adminsadmin90
Mantis-Operatorsoperator50
Mantis-Viewersviewer30
Everyoneviewer10

With this configuration:

  • Users in Mantis-SuperAdmins get admin role
  • Users in Mantis-Operators get operator role
  • Users in only Everyone get viewer role
100+ : Critical/emergency access
90 : Full admin access
50 : Standard operational roles
30 : Limited access roles
10 : Default/catch-all roles

Group names must match exactly (case-sensitive):

IdP Group: "Mantis-Admins" ✓ Matches "Mantis-Admins"
IdP Group: "Mantis-Admins" ✗ Does not match "mantis-admins"
IdP Group: "Mantis-Admins" ✗ Does not match "Mantis Admins"
ProviderGroup FormatExample
OktaGroup nameMantis-Admins
Azure ADObject ID or name12345678-... or Mantis-Admins
KeycloakGroup path/organization/team/admins
Auth0Role/group nameMantis:admin

Azure AD may send group Object IDs instead of names:

{
"groups": [
"12345678-abcd-1234-abcd-123456789012",
"87654321-dcba-4321-dcba-987654321098"
]
}

Create mappings using Object IDs:

INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
VALUES ('$provider_id_uuid', '12345678-abcd-1234-abcd-123456789012', '$role_id_uuid');

A single IdP group can map to multiple Mantis roles:

-- DevOps group gets both operator and target-manager roles
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
SELECT
(SELECT id FROM identity_providers WHERE name = 'Okta'),
'DevOps',
id
FROM roles WHERE name IN ('operator', 'target-manager');

Users in multiple groups receive all mapped roles (additive):

IdP Groups: [Mantis-Operators, Mantis-Deployers]
Mappings:
- Mantis-Operators → operator
- Mantis-Deployers → deployer
Result: User gets [operator, deployer]
# Pseudocode
def sync_additive(user, idp_groups, mappings):
for group in idp_groups:
if group in mappings:
for role in mappings[group]:
if role not in user.roles:
user.roles.append(role)
# Pseudocode
def sync_full(user, idp_groups, mappings):
mapped_roles = set()
for group in idp_groups:
if group in mappings:
mapped_roles.update(mappings[group])
# Add new roles
for role in mapped_roles:
if role not in user.roles:
user.roles.append(role)
# Remove unmapped roles (except system roles)
for role in user.roles:
if role in all_mapped_roles and role not in mapped_roles:
if not role.is_system:
user.roles.remove(role)
-- Admin tier
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id, priority)
VALUES ($provider, 'Mantis-Admins', $admin_role, 100);
-- Operator tier
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id, priority)
VALUES ($provider, 'Mantis-Operators', $operator_role, 50);
-- Viewer tier (default)
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id, priority)
VALUES ($provider, 'Everyone', $viewer_role, 10);
-- Production admins
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
VALUES ($provider, 'Prod-Admins', $prod_admin_role);
-- Staging admins
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
VALUES ($provider, 'Staging-Admins', $staging_admin_role);
-- Development access
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
VALUES ($provider, 'Developers', $dev_role);
-- Tenant A operators
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
VALUES ($provider_tenant_a, 'TenantA-Operators', $operator_role);
-- Tenant B operators
INSERT INTO identity_provider_role_mappings (provider_id, external_group, role_id)
VALUES ($provider_tenant_b, 'TenantB-Operators', $operator_role);
  1. Verify groups claim:

    Terminal window
    # Check if groups are in ID token
    curl -s "https://api.mantis.local/api/v1/auth/oidc/providers"
  2. Check claim configuration:

    SELECT groups_claim FROM identity_providers WHERE id = $provider_id;
  3. Verify mapping exists:

    SELECT * FROM identity_provider_role_mappings
    WHERE provider_id = $provider_id;
  1. Check sync mode:

    SELECT role_sync_mode FROM identity_providers WHERE id = $provider_id;
  2. Verify group names match exactly

  3. Check priority order of mappings

  1. Verify group membership in IdP
  2. Check if role is system role (won’t be removed)
  3. Consider switching to additive mode
  1. Configure groups scope in IdP
  2. Add groups claim to ID token configuration
  3. Check group limit (some IdPs limit groups returned)
ApproachExample
Application prefixMantis-Admins, Mantis-Operators
Role suffixPlatform-Admin, Platform-Viewer
Clear hierarchyOrg/Team/Role
  1. Use additive mode unless full control needed
  2. Audit mappings regularly
  3. Test changes in staging first
  4. Document mappings for operations team
  5. Review role assignments periodically in the Mantis UI
  1. Review before production deployment
  2. Notify affected users of changes
  3. Have rollback plan ready
  4. Test with representative users