Keycloak Role & Domain Mappers (multi-domain / user-group support)

This is the single, login-type-neutral procedure for making Keycloak translate a user’s Active Directory group membership into the two application claims the backend needs:

  • user-group — the application user-group (role) name, and

  • domain — the application domain name (Super domain = full access, domainId = 0).

It is shared verbatim by the ldap and windows login types — both use the same realm, the same LDAP federation and the same mappers, and differ only in how Keycloak authenticates the user (the login form vs. silent Kerberos / SPNEGO). Configure it once per realm and it applies to whichever login type that portal uses.

When you need this — multi-domain / multi-role support

This is what enables multi-domain and multi-role deployments: each AD group carries an attribute holding the application name, Keycloak emits it as a claim, and the backend resolves permissions and domain visibility from it. Directory naming (AdminRole, SuperDomainRole) stays independent of application naming (admin, Super domain).

If every user should simply land in one fixed user-group and the super domain, you still need the user-group mapper, but the domain side can be left as a single Super domain group.

1. Prerequisites

Before configuring the mappers below, the following must already exist — from your login type’s setup guide:

  • A realm per portal (e.g. oneiot-sc, oneiot-mc) with a confidential OIDC client. See LDAP Login via Keycloak (OIDC) or Windows (AD / Kerberos) SSO for the realm and client setup.

  • LDAP User Federation connected to Active Directory, with a group mapper, and the AD groups synced into Keycloak (User federation > the provider > Mappers > the group mapper > Action → Sync LDAP groups to Keycloak). The groups must be visible under Groups before their translation attributes can be set.

  • One role group and one domain group per user in AD.

One user-group and one domain per user

Both claims are single-valued: the backend stores one userGroupId and one domainId per user. A user must therefore belong to exactly one AD role group and exactly one AD domain group. Membership in two groups of the same kind makes the resulting value non-deterministic.

The claim value must exactly match a name in the backend database

The backend matches claim values by name: the user-group value must be identical to a user-group that already exists in the database for that portal, and the domain value to an existing domain (or the literal Super domain). Nothing is provisioned on the fly — if the name is unknown, access is blocked (NO_MATCH_AUTH, HTTP 403). The AD group name itself does not have to match; Keycloak translates it (Step 1).

2. Step 1 — Translation attributes on groups

This is where the AD group name is translated into the application name. Each group carries one attribute; the attribute name decides which claim it feeds.

AD group Attribute key Attribute value

AdminRole

user-group

admin

UserRole

user-group

user

SuperDomainRole

domain

Super domain

For each group: open Groups > the group > Attributes, click Add attributes, fill in the key and value, and click Save.

Group AdminRole — attribute user-group with value admin
Group SuperDomainRole — attribute domain with value Super domain
The value is the application name, spelled exactly

The attribute value must match a user-group or domain that exists in the backend database for that portal. Super domain is spelled with a lower-case d and is recognised by exact name — it grants access to every domain (domainId = 0).

This replaces the older arrangement in which AD groups had to be named exactly like the application user-groups. With the translation attribute, directory naming and application naming are independent.

3. Step 2 — Protocol mappers (per client)

The ID token must carry three custom claims: portal-type, user-group, and domain. The username arrives in the standard preferred_username claim and needs no mapper. Add the mappers to the client’s dedicated scope, in each realm.

  1. Switch to the target realm and open Clients > your client > Client scopes.

  2. Click the client’s dedicated scope — the first row, described as "Dedicated scope and mappers for this client".

Client scopes tab — the dedicated scope is the first row
Mappers of the client’s dedicated scope
  1. Click Add mapper > By configuration and create the mappers below.

Add mapper menu — From predefined mappers / By configuration
Remove obsolete hardcoded mappers first

Earlier revisions configured user-group as a Group Membership mapper and domain as a Hardcoded claim. Both are superseded. If mappers with those claim names are already present, delete them (row menu …​ → Delete) before adding the ones below — a leftover hardcoded mapper emits the same value for every user and overrides the translation.

3.1. portal-type (Hardcoded claim)

Field Value

Mapper type

Hardcoded claim

Name

portal-type

Token Claim Name

portal-type

Claim value

sc in realm oneiot-sc, mc in realm oneiot-mc

Claim JSON Type

String

Add to ID token

On

3.2. user-group (User Attribute)

Both remaining mappers use the same type, User Attribute, and differ only in the name. In the type picker, scroll down to User Attribute — not User Client Role or User Property.

Mapper type picker — User Attribute
Field Value

Mapper type

User Attribute

Name

user-group

User Attribute

user-group

Token Claim Name

user-group

Claim JSON Type

String

Add to ID token

On

Add to access token

On

Multivalued

Off

Aggregate attribute values

Off

User Attribute mapper — name
User Attribute mapper — Multivalued and Aggregate attribute values switched off
Why Multivalued and Aggregate stay off

Role and domain are one value per user. With Aggregate attribute values off, Keycloak returns the value of the first group that carries the attribute and skips groups that do not — exactly the required behaviour. Leaving Multivalued off keeps the claim a plain string rather than an array.

3.3. domain (User Attribute)

Identical to the previous mapper, with domain substituted everywhere.

Field Value

Mapper type

User Attribute

Name

domain

User Attribute

domain

Token Claim Name

domain

Claim JSON Type

String

Add to ID token

On

Add to access token

On

Multivalued / Aggregate attribute values

Off / Off

Second User Attribute mapper configured for the domain claim
The Token Claim Name values must be exactly portal-type, user-group, and domain — the backend expects these fixed names and has no override for them. The claim values come from the group attributes configured in Step 1 — Translation attributes on groups and must match names that exist in the backend database.

4. Step 3 — Verify the claims without logging in

Keycloak can assemble a token for any user from the Admin Console, which verifies the whole chain without disturbing anyone’s session.

  1. Open Clients > your client > Client scopes > Evaluate.

  2. Start typing a login in the Users field and pick the user from the suggestions.

Evaluate tab — selecting a user
  1. On the right, click Generated ID token.

Generated ID token containing the domain and user-group claims

The configuration is correct when both claims are present as plain strings:

"domain": "Super domain",
"user-group": "admin",
An array (["admin"]) instead of a string means Multivalued is still enabled on the mapper.
Diagnose from the token backwards

Work the chain in this order: the generated ID token (Client scopes → Evaluate), then the user’s Groups tab, then the group’s Attributes tab (Step 1), then the federation’s group mapper. The first step that shows the wrong value is the layer that is broken.

5. Checklist

  • AD groups synced into Keycloak and visible under Groups.

  • A user-group attribute set on each role group, and a domain attribute on each domain group (Step 1); values match names that exist in the backend database for that portal.

  • Protocol mappers on the client’s dedicated scope (Step 2): user-group and domain (both User Attribute, Multivalued / Aggregate off) plus portal-type (hardcoded sc/mc).

  • No leftover Hardcoded claim or Group Membership mappers for user-group / domain.

  • Evaluate shows both claims as plain strings (Step 3).