Keycloak Role & Domain Mappers

Whatever the login type — ldap, windows or saml — the backend requires the same three claims on every token, and refuses the login if any of them is missing or unknown:

  • portal-type — which portal the token is for (sc / mc),

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

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

This page is the single, login-type-neutral procedure for producing them. 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.

1. Prerequisites

Whichever mode you pick, 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. This is what authenticates the user and supplies preferred_username, in both modes.

  • Mode B only: a group mapper on the federation, with 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, and each user must be in one role group and one domain group.

2. Choose a mode

How the user-group and domain claims are produced depends on whether the deployment needs more than one application user-group or more than one domain. Pick one mode per realm and configure all three claims accordingly — the two modes are not mixed.

Mode Use when How the claims are produced

A — Single user-group, single domain

Every SSO user should land in the same application user-group and in the super domain. No per-user role or domain distinction is needed.

All three claims are Hardcoded claim mappers, exactly as portal-type already is. No AD group attributes, no group sync for claim purposes.

B — Multi user-group / multi-domain

Different users must land in different user-groups, different domains, or both.

user-group and domain are User Attribute mappers fed by translation attributes on the user’s AD groups (Steps 1-3 below). portal-type stays hardcoded.

A missing claim blocks the login — in both modes

OidcAuthService never provisions anything on the fly. If user-group or domain is absent from the token, or carries a name that does not exist in the backend database for that portal, the user is rejected with NO_MATCH_AUTH (HTTP 403) after Keycloak has authenticated them.

This is deliberate for domain as well as for user-group: the backend reads a missing domain as no domain grant, not as an implicit one. Mode A satisfies the requirement by emitting a fixed value for everyone; Mode B satisfies it by requiring each user to be in exactly one role group and exactly one domain group.

Never configure both modes for the same claim

A Hardcoded claim mapper and a User Attribute mapper carrying the same Token Claim Name must not coexist on a client: the hardcoded value is emitted for every user and overrides the translation, which silently collapses a multi-domain deployment into a single domain. When switching a realm from Mode A to Mode B, delete the hardcoded user-group / domain mappers before adding the User Attribute ones (and the reverse when moving back).

3. Mode A — Single user-group and domain (hardcoded claims)

Add three Hardcoded claim mappers to the client’s dedicated scope (Clients > your client > Client scopes > <client>-dedicated > Add mapper > By configuration > Hardcoded claim). Field-by-field, they are identical to the portal-type mapper described in portal-type (Hardcoded claim); only the name and value differ.

Token Claim Name Claim value Notes

portal-type

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

Always hardcoded, in both modes.

user-group

The application user-group every SSO user should get, e.g. Admin

Must already exist in the backend database for that portal (Settings > User groups). It is never created automatically.

domain

Super domain

Resolves to domainId = 0 — access to every domain. Any other value must be an existing domain name.

Set Claim JSON Type to String and Add to ID token / Add to access token to On for all three, then verify with Step 3 — Verify the claims without logging in — the check is the same in both modes.

In this mode the AD groups need no translation attributes, so Mode B’s Steps 1 and 2 do not apply — only Step 3, to confirm the claims actually reach the token.

Mode A is the shortest path to a working SSO login, and it is a valid permanent configuration for single-tenant deployments — not just a starting point. Moving to Mode B later only requires replacing the two hardcoded mappers, not reworking the realm.

4. Mode B — Multi user-group / multi-domain

The rest of this page describes Mode B: 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).

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

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

4.2. 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 any hardcoded user-group / domain mappers first

These mappers replace the Mode A ones. If mappers with the user-group or domain claim names are already present — whether from a Mode A setup or from an earlier revision that configured user-group as a Group Membership mapper — 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, so every user silently lands in the same group and domain.

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

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

4.2.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.3. 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

Mode A — single user-group and domain:

  • Three Hardcoded claim mappers on the client’s dedicated scope: portal-type, user-group, domain.

  • The hardcoded user-group value exists in the backend database for that portal; the domain value is Super domain or an existing domain name.

  • No User Attribute mappers for user-group / domain left on the client.

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

Mode B — multi user-group / multi-domain:

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

  • Every user is in exactly one role group and exactly one domain group — a user missing either one is rejected at login.

  • 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).