This article presents a comprehensive best-practice approach for designing a multi-organization authentication and authorization system in Keycloak using a single realm. It specifically focuses on leveraging Keycloak's built-in token mapper functionality to effectively inject organization-related data into tokens, enabling streamlined and secure application-level authorization.


📌 Goals of This Approach

  • Single-Realm Simplicity: Manage multiple organizations efficiently within one Keycloak realm.
  • Clear Organization Boundaries: Ensure users access only resources within their designated organizations.
  • Token Clarity: Embed clear, structured organization information into tokens.
  • Flexible Authorization: Allow easy application-level enforcement of organizational access control.

Core Keycloak Setup

1. Single Realm Configuration

Use a single Keycloak realm (e.g., myrealm) for ease of administration and centralized user management.


2. Representing Organizations with Groups

Define a clear, hierarchical group structure to represent organizations:

Recommended Structure Example:

/orgs
  ├── acme
  │   ├── departments
  │   │   ├── sales
  │   │   └── engineering
  └── contoso
      └── regions
          ├── europe
          └── asia
  • Each top-level group under /orgs represents a distinct organization.
  • Nested groups represent departments, regions, or subdivisions.

3. Scoped Roles with Organization Prefixes

Create organization-specific roles to clearly scope permissions:

Organization Example Roles
Acme acme_admin, acme_manager, acme_user
Contoso contoso_admin, contoso_manager, contoso_user

Assign these roles directly to users or automatically via group membership.


Injecting Organization Information into Tokens

To enable effective authorization, the user's JWT token must clearly convey organizational memberships. We achieve this with Keycloak's token mappers.

Organization Identification Strategies

Choose one strategy clearly defining organization groups:

  • Naming Convention: Prefix groups (org_acme).
  • Group Attribute: Set is_organization=true on organization root groups.
  • Path Pattern: Organizations under /orgs/{org_name} path (recommended simple approach).

Configuring Keycloak Token Mappers

Basic Group Membership Mapper (Recommended for Simplicity)

  1. Navigate to:

    Client Scopes → select your scope (or create one named "organizations") → MappersAdd Mapper.

  2. Create a new "Group Membership" mapper with settings:

    • Name: organization_groups
    • Mapper Type: Group Membership
    • Token Claim Name: orgs
    • Full group path: ON
    • Filter (Regex): ^/orgs/[^/]+$ (captures only direct organization groups)

Resulting Token Claim Example:

{
  "orgs": ["/orgs/acme", "/orgs/contoso"]
}

Advanced: Script Mapper for Complex Organization Structures

For scenarios involving deeper hierarchies or attributes:

  1. Create a new "Script Mapper":

    • Name: organization_hierarchy
    • Mapper Type: Script Mapper
    • Token Claim Name: org_hierarchy
  2. Script Example (JavaScript):

function isOrganizationGroup(group) {
    return group.getPath().matches("^/orgs/[^/]+$");
}

function getOrganizationAncestry(group) {
    var segments = group.getPath().split("/");
    var orgPaths = [];
    for (var i = 2; i < segments.length; i++) {
        orgPaths.push(segments.slice(0, i + 1).join("/"));
    }
    return orgPaths;
}

var orgHierarchy = user.getGroups().stream()
    .flatMap(function(group) {
        return getOrganizationAncestry(group).stream();
    })
    .distinct()
    .collect(Collectors.toList());

exports = orgHierarchy;

Resulting Token Claim Example:

{
  "org_hierarchy": [
    "/orgs/acme",
    "/orgs/acme/departments",
    "/orgs/acme/departments/sales"
  ]
}

Including Mappers in Client Configuration

  • Attach your custom client scope (with these mappers) to Keycloak client configurations.
  • Ensure mapper output is included in either access tokens, ID tokens, or both as needed.

Application-Level Authorization Logic

Applications extract organization information directly from JWT tokens:

Example (Python Flask):

def get_user_organizations(token):
    orgs = token.get('orgs', [])
    hierarchy = token.get('org_hierarchy', [])
    return {
        'flat_orgs': orgs,
        'hierarchy': hierarchy
    }

Authorization Middleware Example (Express.js):

function orgAccessMiddleware(req, res, next) {
  const requiredOrg = req.params.orgId;
  const userOrgs = req.user.token.orgs;

  const hasAccess = userOrgs.some(orgPath => 
    orgPath === `/orgs/${requiredOrg}` || 
    orgPath.startsWith(`/orgs/${requiredOrg}/`)
  );

  if (!hasAccess) {
    return res.status(403).send('Access denied to organization');
  }

  next();
}

Performance and Maintenance Considerations

Token Size Management

  • Keep hierarchy depth reasonable to prevent token bloat.
  • Regularly review and optimize mapper scripts.

Caching and Lazy Loading

  • Cache organizational hierarchies in applications.
  • Consider lazy-loading additional details for very large organizations.

Automation and Documentation

  • Automate group and role creation using Keycloak Admin API.
  • Clearly document organizational conventions and structures.

Summary of Recommended Approach

Component Recommended Practice Advantage
Realm Single-realm Simplified administration
Organizations Groups (/orgs/{org_name}) Clear hierarchical organization
Roles Scoped with org-prefix (acme_user) Avoid role conflicts
Token Mappers Group Membership & Script Mapper Clear organization claims in tokens
Application Logic JWT-based organization checks Secure, clear authorization logic
Automation Keycloak Admin API Efficient onboarding and maintenance

Example Workflow

  • User Login: Alice logs in through Keycloak.
  • Token Issued: Token includes:
"orgs": ["/orgs/acme"],
  "realm_access": {"roles": ["acme_manager"]}
  • Resource Access: Alice accesses /acme/reports.
  • Authorization Check: App confirms:
    • Alice is in /orgs/acme ✔️
    • Alice has role acme_manager ✔️
  • Access Granted ✔️

🚀 Conclusion

Leveraging Keycloak's built-in token mappers within a structured, single-realm configuration provides a robust, maintainable, and secure way to manage multi-organization access control. Clearly embedding organization details into tokens empowers your applications to enforce precise, efficient authorization rules.