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)
Navigate to:
Client Scopes
→ select your scope (or create one named "organizations") →Mappers
→Add Mapper
.-
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)
-
Name:
Resulting Token Claim Example:
{
"orgs": ["/orgs/acme", "/orgs/contoso"]
}
Advanced: Script Mapper for Complex Organization Structures
For scenarios involving deeper hierarchies or attributes:
-
Create a new "Script Mapper":
-
Name:
organization_hierarchy
-
Mapper Type:
Script Mapper
-
Token Claim Name:
org_hierarchy
-
Name:
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
✔️
- Alice is in
- 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.