0
# Organization Management
1
2
Organization management provides multi-tenant capabilities within Keycloak, allowing for the creation and management of organizations with their own members, identity providers, and domain-based authentication routing. This SPI enables enterprise scenarios where multiple organizations share a single Keycloak realm while maintaining organizational boundaries.
3
4
## Capabilities
5
6
### Organization Provider
7
8
The primary interface for managing organizations and their associated data within a realm.
9
10
```java { .api }
11
/**
12
* A Provider that manages organization and its data within the scope of a realm.
13
*/
14
public interface OrganizationProvider extends Provider {
15
16
/**
17
* Creates a new organization with given name and alias to the realm.
18
* @param name the name of the organization
19
* @param alias the alias of the organization. If not set, defaults to name. Once set, the alias is immutable
20
* @throws ModelDuplicateException If there is already an organization with the given name or alias
21
* @return Model of the created organization
22
*/
23
OrganizationModel create(String name, String alias);
24
25
/**
26
* Creates a new organization with given id, name, and alias to the realm
27
* @param id the id of the organization
28
* @param name the name of the organization
29
* @param alias the alias of the organization
30
* @throws ModelDuplicateException If there is already an organization with the given name or alias
31
* @return Model of the created organization
32
*/
33
OrganizationModel create(String id, String name, String alias);
34
35
/**
36
* Returns an OrganizationModel by its id
37
* @param id the id of an organization
38
* @return the organization with the given id or null if there is no such organization
39
*/
40
OrganizationModel getById(String id);
41
42
/**
43
* Returns an OrganizationModel by its internet domain
44
* @param domainName the organization's internet domain (e.g. redhat.com)
45
* @return the organization that is linked to the given internet domain
46
*/
47
OrganizationModel getByDomainName(String domainName);
48
49
/**
50
* Returns an OrganizationModel with the given alias
51
* @param alias the alias
52
* @return the organization
53
*/
54
OrganizationModel getByAlias(String alias);
55
56
/**
57
* Returns all organizations in the realm
58
* @return a Stream of the realm's organizations
59
*/
60
Stream<OrganizationModel> getAllStream();
61
62
/**
63
* Returns all organizations in the realm filtered according to the specified parameters
64
* @param search a String representing either an organization name or domain
65
* @param exact if true, organizations will be searched using exact match
66
* @param first the position of the first result to be processed (pagination offset)
67
* @param max the maximum number of results to be returned
68
* @return a Stream of the matched organizations
69
*/
70
Stream<OrganizationModel> getAllStream(String search, Boolean exact, Integer first, Integer max);
71
72
/**
73
* Returns all organizations in the realm filtered according to the specified parameters
74
* @param attributes a Map containing the attributes (name/value) that must match organization attributes
75
* @param first the position of the first result to be processed (pagination offset)
76
* @param max the maximum number of results to be returned
77
* @return a Stream of the matched organizations
78
*/
79
Stream<OrganizationModel> getAllStream(Map<String, String> attributes, Integer first, Integer max);
80
81
/**
82
* Removes the given organization from the realm together with the data associated with it
83
* @param organization Organization to be removed
84
* @throws ModelException if the organization doesn't exist or doesn't belong to the realm
85
* @return true if the organization was removed, false otherwise
86
*/
87
boolean remove(OrganizationModel organization);
88
89
/**
90
* Removes all organizations from the realm
91
*/
92
void removeAll();
93
94
/**
95
* Returns number of organizations in the realm
96
* @return Number of organizations
97
*/
98
long count();
99
100
/**
101
* Indicates if the current realm supports organization
102
* @return true if organization is supported, false otherwise
103
*/
104
boolean isEnabled();
105
}
106
```
107
108
### Organization Member Management
109
110
Comprehensive member management with support for both managed and unmanaged members.
111
112
```java { .api }
113
public interface OrganizationProvider extends Provider {
114
115
/**
116
* Adds the given UserModel as a managed member of the given OrganizationModel.
117
* @param organization the organization
118
* @param user the user
119
* @throws ModelException if the UserModel is member of different organization
120
* @return true if the user was added as a member, false otherwise
121
*/
122
boolean addManagedMember(OrganizationModel organization, UserModel user);
123
124
/**
125
* Adds the given UserModel as an unmanaged member of the given OrganizationModel.
126
* @param organization the organization
127
* @param user the user
128
* @throws ModelException if the UserModel is member of different organization
129
* @return true if the user was added as a member, false otherwise
130
*/
131
boolean addMember(OrganizationModel organization, UserModel user);
132
133
/**
134
* Returns the members of a given OrganizationModel filtered according to the specified filters.
135
* @param organization the organization
136
* @param filters Map containing filters for member search
137
* @param exact if true, exact match for filters
138
* @param first the position of the first result (pagination offset)
139
* @param max the maximum number of results to be returned
140
* @return Stream of the members
141
*/
142
Stream<UserModel> getMembersStream(OrganizationModel organization, Map<String, String> filters, Boolean exact, Integer first, Integer max);
143
144
/**
145
* Returns number of members in the organization
146
* @param organization the organization
147
* @return Number of members in the organization
148
*/
149
long getMembersCount(OrganizationModel organization);
150
151
/**
152
* Returns the member of the OrganizationModel by its id
153
* @param organization the organization
154
* @param id the member id
155
* @return the member of the OrganizationModel with the given id
156
*/
157
UserModel getMemberById(OrganizationModel organization, String id);
158
159
/**
160
* Returns the OrganizationModel that the member belongs to
161
* @param member the member of an organization
162
* @return the organizations the member belongs to or an empty stream if the user doesn't belong to any
163
*/
164
Stream<OrganizationModel> getByMember(UserModel member);
165
166
/**
167
* Indicates if the given member is managed by the organization.
168
* A member is managed by the organization whenever the member cannot exist without the organization
169
* @param organization the organization
170
* @param member the member
171
* @return true if the member is managed by the given organization
172
*/
173
boolean isManagedMember(OrganizationModel organization, UserModel member);
174
175
/**
176
* Indicates if the given user is a member of the given organization
177
* @param organization the organization
178
* @param user the member
179
* @return true if the user is a member, false otherwise
180
*/
181
boolean isMember(OrganizationModel organization, UserModel user);
182
183
/**
184
* Removes a member from the organization.
185
* This method can either remove the given member entirely from the realm or only remove the link to the organization.
186
* The decision depends on whether the user is managed by the organization or not.
187
* @param organization the organization
188
* @param member the member
189
* @return true if the given member is a member and was successfully removed from the organization
190
*/
191
boolean removeMember(OrganizationModel organization, UserModel member);
192
}
193
```
194
195
### Identity Provider Association
196
197
Associate identity providers with organizations for automatic user routing and federated authentication.
198
199
```java { .api }
200
public interface OrganizationProvider extends Provider {
201
202
/**
203
* Associate the given IdentityProviderModel with the given OrganizationModel
204
* @param organization the organization
205
* @param identityProvider the identityProvider
206
* @return true if the identityProvider was associated with the organization, false otherwise
207
*/
208
boolean addIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider);
209
210
/**
211
* Returns Stream of the identity providers associated with the given organization
212
* @param organization the organization
213
* @return Stream of the identity providers associated with the organization
214
*/
215
Stream<IdentityProviderModel> getIdentityProviders(OrganizationModel organization);
216
217
/**
218
* Removes the link between the given OrganizationModel and the identity provider if such a link exists
219
* @param organization the organization
220
* @param identityProvider the identity provider
221
* @return true if the link was removed, false otherwise
222
*/
223
boolean removeIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider);
224
}
225
```
226
227
### Organization Model
228
229
The core model representing an organization with its attributes, domains, and configuration.
230
231
```java { .api }
232
/**
233
* Model representation of an organization within a realm.
234
*/
235
public interface OrganizationModel {
236
237
String ORGANIZATION_ATTRIBUTE = "kc.org";
238
String ORGANIZATION_NAME_ATTRIBUTE = "kc.org.name";
239
String ORGANIZATION_DOMAIN_ATTRIBUTE = "kc.org.domain";
240
String ALIAS = "alias";
241
242
/**
243
* Identity provider redirect modes for organization-based routing.
244
*/
245
enum IdentityProviderRedirectMode {
246
EMAIL_MATCH("kc.org.broker.redirect.mode.email-matches");
247
248
private final String key;
249
250
IdentityProviderRedirectMode(String key) {
251
this.key = key;
252
}
253
254
public boolean isSet(IdentityProviderModel broker) {
255
return Boolean.parseBoolean(broker.getConfig().get(key));
256
}
257
258
public String getKey() {
259
return key;
260
}
261
}
262
263
/**
264
* Returns the unique identifier of the organization
265
* @return the organization ID
266
*/
267
String getId();
268
269
/**
270
* Sets the name of the organization
271
* @param name the organization name
272
*/
273
void setName(String name);
274
275
/**
276
* Returns the name of the organization
277
* @return the organization name
278
*/
279
String getName();
280
281
/**
282
* Returns the alias of the organization
283
* @return the organization alias
284
*/
285
String getAlias();
286
287
/**
288
* Sets the alias of the organization
289
* @param alias the organization alias
290
*/
291
void setAlias(String alias);
292
293
/**
294
* Returns whether the organization is enabled
295
* @return true if enabled, false otherwise
296
*/
297
boolean isEnabled();
298
299
/**
300
* Sets whether the organization is enabled
301
* @param enabled true to enable, false to disable
302
*/
303
void setEnabled(boolean enabled);
304
305
/**
306
* Returns the description of the organization
307
* @return the organization description
308
*/
309
String getDescription();
310
311
/**
312
* Sets the description of the organization
313
* @param description the organization description
314
*/
315
void setDescription(String description);
316
317
/**
318
* Returns the redirect URL for the organization
319
* @return the redirect URL
320
*/
321
String getRedirectUrl();
322
323
/**
324
* Sets the redirect URL for the organization
325
* @param redirectUrl the redirect URL
326
*/
327
void setRedirectUrl(String redirectUrl);
328
329
/**
330
* Returns the organization's attributes
331
* @return Map of organization attributes
332
*/
333
Map<String, List<String>> getAttributes();
334
335
/**
336
* Sets the organization's attributes
337
* @param attributes Map of organization attributes
338
*/
339
void setAttributes(Map<String, List<String>> attributes);
340
341
/**
342
* Returns the domains associated with the organization
343
* @return Stream of organization domains
344
*/
345
Stream<OrganizationDomainModel> getDomains();
346
347
/**
348
* Sets the domains associated with the organization
349
* @param domains Set of organization domains
350
*/
351
void setDomains(Set<OrganizationDomainModel> domains);
352
353
/**
354
* Returns the identity providers associated with the organization
355
* @return Stream of identity providers
356
*/
357
Stream<IdentityProviderModel> getIdentityProviders();
358
359
/**
360
* Indicates if the given user is managed by the organization
361
* @param user the user
362
* @return true if the user is managed by the organization
363
*/
364
boolean isManaged(UserModel user);
365
366
/**
367
* Indicates if the given user is a member of the organization
368
* @param user the user
369
* @return true if the user is a member of the organization
370
*/
371
boolean isMember(UserModel user);
372
}
373
```
374
375
### Organization Domain Model
376
377
Model representing internet domains associated with organizations for email-based routing and verification.
378
379
```java { .api }
380
/**
381
* Model implementation of an organization internet domain.
382
*/
383
public class OrganizationDomainModel implements Serializable {
384
385
/**
386
* Value used to link an identity provider with all domains from the organization.
387
* If the user's email domain matches any of the organization domains, automatic redirection will be performed.
388
*/
389
public static final String ANY_DOMAIN = "ANY";
390
391
/**
392
* Creates a new domain model with the given name (unverified by default)
393
* @param name the domain name
394
*/
395
public OrganizationDomainModel(String name);
396
397
/**
398
* Creates a new domain model with the given name and verification status
399
* @param name the domain name
400
* @param verified whether the domain is verified
401
*/
402
public OrganizationDomainModel(String name, boolean verified);
403
404
/**
405
* Returns the domain name
406
* @return the domain name
407
*/
408
public String getName();
409
410
/**
411
* Returns whether the domain is verified
412
* @return true if verified, false otherwise
413
*/
414
public boolean isVerified();
415
}
416
```
417
418
### Organization Events
419
420
Event interfaces for organization membership lifecycle management.
421
422
```java { .api }
423
public interface OrganizationModel {
424
425
/**
426
* Base interface for organization membership events
427
*/
428
interface OrganizationMembershipEvent extends ProviderEvent {
429
OrganizationModel getOrganization();
430
UserModel getUser();
431
KeycloakSession getSession();
432
}
433
434
/**
435
* Event fired when a user joins an organization
436
*/
437
interface OrganizationMemberJoinEvent extends OrganizationMembershipEvent {
438
static void fire(OrganizationModel organization, UserModel user, KeycloakSession session);
439
}
440
441
/**
442
* Event fired when a user leaves an organization
443
*/
444
interface OrganizationMemberLeaveEvent extends OrganizationMembershipEvent {
445
static void fire(OrganizationModel organization, UserModel user, KeycloakSession session);
446
}
447
}
448
```
449
450
## Usage Examples
451
452
### Creating and Managing Organizations
453
454
```java
455
import org.keycloak.organization.OrganizationProvider;
456
import org.keycloak.models.OrganizationModel;
457
import org.keycloak.models.OrganizationDomainModel;
458
import org.keycloak.models.KeycloakSession;
459
460
public class OrganizationManagementExample {
461
462
public void createOrganization(KeycloakSession session) {
463
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
464
465
// Create a new organization
466
OrganizationModel org = provider.create("Example Corp", "example-corp");
467
org.setDescription("Example Corporation for demonstrating organization management");
468
org.setEnabled(true);
469
470
// Add domains to the organization
471
Set<OrganizationDomainModel> domains = new HashSet<>();
472
domains.add(new OrganizationDomainModel("example.com", true)); // verified domain
473
domains.add(new OrganizationDomainModel("example.org", false)); // unverified domain
474
org.setDomains(domains);
475
476
// Set custom attributes
477
Map<String, List<String>> attributes = new HashMap<>();
478
attributes.put("industry", Arrays.asList("Technology"));
479
attributes.put("size", Arrays.asList("Enterprise"));
480
org.setAttributes(attributes);
481
}
482
483
public void findOrganizationByDomain(KeycloakSession session, String email) {
484
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
485
486
// Extract domain from email
487
String domain = email.substring(email.indexOf("@") + 1);
488
489
// Find organization by domain
490
OrganizationModel org = provider.getByDomainName(domain);
491
if (org != null) {
492
System.out.println("Found organization: " + org.getName());
493
}
494
}
495
}
496
```
497
498
### Managing Organization Members
499
500
```java
501
public class OrganizationMembershipExample {
502
503
public void manageMembership(KeycloakSession session, RealmModel realm) {
504
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
505
OrganizationModel org = provider.getByAlias("example-corp");
506
507
// Add a managed member (lifecycle bound to organization)
508
UserModel managedUser = session.users().getUserByEmail(realm, "employee@example.com");
509
if (managedUser != null) {
510
provider.addManagedMember(org, managedUser);
511
}
512
513
// Add an unmanaged member (existing user joining organization)
514
UserModel unmanagedUser = session.users().getUserByEmail(realm, "partner@otherdomain.com");
515
if (unmanagedUser != null) {
516
provider.addMember(org, unmanagedUser);
517
}
518
519
// Search members with filters
520
Map<String, String> filters = new HashMap<>();
521
filters.put(UserModel.SEARCH, "john");
522
filters.put(MembershipType.NAME, MembershipType.MANAGED.name());
523
524
Stream<UserModel> managedMembers = provider.getMembersStream(org, filters, false, 0, 10);
525
managedMembers.forEach(user -> {
526
System.out.println("Managed member: " + user.getEmail());
527
});
528
529
// Get member count
530
long memberCount = provider.getMembersCount(org);
531
System.out.println("Total members: " + memberCount);
532
}
533
534
public void checkMembershipStatus(KeycloakSession session, UserModel user) {
535
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
536
537
// Find all organizations the user belongs to
538
Stream<OrganizationModel> userOrganizations = provider.getByMember(user);
539
userOrganizations.forEach(org -> {
540
boolean isManaged = provider.isManagedMember(org, user);
541
System.out.println("User is " + (isManaged ? "managed" : "unmanaged") +
542
" member of " + org.getName());
543
});
544
}
545
}
546
```
547
548
### Identity Provider Association
549
550
```java
551
public class OrganizationIdentityProviderExample {
552
553
public void associateIdentityProvider(KeycloakSession session, RealmModel realm) {
554
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
555
OrganizationModel org = provider.getByAlias("example-corp");
556
557
// Get an identity provider
558
IdentityProviderModel idp = realm.getIdentityProviderByAlias("corporate-saml");
559
560
if (idp != null) {
561
// Associate identity provider with organization
562
boolean associated = provider.addIdentityProvider(org, idp);
563
564
if (associated) {
565
// Configure email-based routing
566
Map<String, String> config = idp.getConfig();
567
config.put(OrganizationModel.IdentityProviderRedirectMode.EMAIL_MATCH.getKey(), "true");
568
idp.setConfig(config);
569
570
realm.updateIdentityProvider(idp);
571
System.out.println("Identity provider associated with organization");
572
}
573
}
574
575
// List all identity providers for the organization
576
Stream<IdentityProviderModel> orgIdps = provider.getIdentityProviders(org);
577
orgIdps.forEach(identityProvider -> {
578
System.out.println("Organization uses IDP: " + identityProvider.getAlias());
579
});
580
}
581
}
582
```
583
584
### Organization Search and Filtering
585
586
```java
587
public class OrganizationSearchExample {
588
589
public void searchOrganizations(KeycloakSession session) {
590
OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
591
592
// Search by name or domain
593
Stream<OrganizationModel> searchResults = provider.getAllStream("example", false, 0, 10);
594
searchResults.forEach(org -> {
595
System.out.println("Found: " + org.getName() + " (" + org.getAlias() + ")");
596
});
597
598
// Search by attributes
599
Map<String, String> attributes = new HashMap<>();
600
attributes.put("industry", "Technology");
601
Stream<OrganizationModel> attrResults = provider.getAllStream(attributes, 0, 10);
602
603
// Get organization count
604
long totalOrgs = provider.count();
605
System.out.println("Total organizations: " + totalOrgs);
606
607
// Check if organizations are enabled in the realm
608
boolean orgEnabled = provider.isEnabled();
609
System.out.println("Organizations enabled: " + orgEnabled);
610
}
611
}
612
```
613
614
Organization management provides a comprehensive framework for multi-tenant scenarios, enabling domain-based user routing, federated identity integration, and hierarchical membership management within Keycloak realms.