Keycloak OIDC protocol mapper that turns group membership into an
orgstoken claim with roles.
kc-groupid-mapper is a custom Keycloak OIDC
protocol mapper. It reads a user's group membership and adds a single claim to
their tokens describing the organizations they belong to and their roles
within each one — derived entirely from the group tree, with no extra data
model.
It is part of the OptimCE platform, where it lets downstream services authorize requests per energy community from the access token alone. It is developed in the OptimCE monorepo and released here as a standalone provider.
The mapper walks each of the user's groups and looks for organization groups under a configurable root path. The expected group layout is:
/orgs
/acme
/roles
/ADMIN
/BILLING
/globex
/roles
/VIEWER
For every organization the user belongs to, it emits one entry containing the
group id (orgId), the group path (orgPath), and the set of roles collected
from the roles/ subgroups. A user who is a member of /orgs/acme/roles/ADMIN,
/orgs/acme/roles/BILLING, and /orgs/globex/roles/VIEWER gets:
"orgs": [
{
"orgId": "3f2a9c14-…",
"orgPath": "/orgs/acme",
"roles": ["ADMIN", "BILLING"]
},
{
"orgId": "9c1b7e08-…",
"orgPath": "/orgs/globex",
"roles": ["VIEWER"]
}
]The claim name (orgs above) is configurable, and the claim can be added to the
access token, the ID token, the UserInfo response, and token introspection.
How roles are extracted from an organization's subgroups depends on the
rolesMode option:
strict(default) — only groups underroles/count, i.e./orgs/<org>/roles/<ROLE>.loose— both/orgs/<org>/roles/<ROLE>and the shorthand/orgs/<org>/<ROLE>count.
Once the provider is deployed, add the Organizations (id/path) with roles
mapper (provider id oidc-orgs-with-roles-mapper) to a client or client scope
and configure:
| Option | Config key | Default | Description |
|---|---|---|---|
| Claim name | claimName |
(empty) | Name of the JWT claim that holds the organizations-with-roles array. |
| Orgs root group path | orgsRootPath |
/ |
Group path whose direct children are organizations, e.g. /orgs. / means top-level groups are organizations. |
| Roles mode | rolesMode |
strict |
strict accepts only /orgs/<org>/roles/<ROLE>; loose also accepts /orgs/<org>/<ROLE>. |
The standard OIDC token-inclusion toggles (add to ID token, access token, lightweight access token, UserInfo, and token introspection) are available as well.
Requires JDK 17 and Maven.
mvn -B packageThis produces the provider JAR at target/kc-groupid-mapper-1.0.0.jar.
Pre-built JARs are also attached to each
GitHub Release.
The provider targets Keycloak 26.5.1.
-
Copy the JAR into Keycloak's providers directory:
cp target/kc-groupid-mapper-1.0.0.jar /opt/keycloak/providers/
-
Rebuild Keycloak so it picks up the new provider:
/opt/keycloak/bin/kc.sh build
-
In the admin console, add the Organizations (id/path) with roles mapper to a client or client scope and set the options above.
To bake it into a Keycloak image, the included Dockerfile builds
the JAR and installs it in one multi-stage build:
FROM maven:3.9.6-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn -B -q -e -DskipTests dependency:go-offline
COPY src ./src
RUN mvn -B -q -DskipTests package
FROM quay.io/keycloak/keycloak:26.5.1
WORKDIR /opt/keycloak
COPY --from=builder /app/target/kc-groupid-mapper-*.jar /opt/keycloak/providers/
RUN /opt/keycloak/bin/kc.sh buildIn the OptimCE realm the mapper is attached to a dedicated client scope with the
claim name orgs and rolesMode set to loose, so that every issued token
carries the caller's communities and their roles. See the Keycloak realm
configuration in the monorepo for the
full setup.
Contributions are welcome! Please read the contributing guidelines and our Code of Conduct before opening an issue or pull request.
To report a security vulnerability, please follow the security policy — do not open a public issue.
This project is licensed under the Apache License 2.0.