keycloak-api-manager 5.0.1 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,615 @@
1
+ # Organizations API
2
+
3
+ Manage organizations for multi-tenancy in Keycloak 25+.
4
+
5
+ **Namespace:** `KeycloakManager.organizations`
6
+ **Keycloak Version:** 25.0+
7
+ **Required Feature Flag:** `organization`
8
+
9
+ ## Overview
10
+
11
+ Organizations provide a way to group users, identity providers, and domains together, enabling better isolation and management of different organizational units in multi-tenant scenarios.
12
+
13
+ ### Enable Organizations Feature
14
+
15
+ Start Keycloak with the organizations feature enabled:
16
+
17
+ ```bash
18
+ --features=organization
19
+ ```
20
+
21
+ Or in `docker-compose.yml`:
22
+
23
+ ```yaml
24
+ environment:
25
+ KC_FEATURES: 'organization'
26
+ ```
27
+
28
+ ## Table of Contents
29
+
30
+ - [create()](#create) - Create an organization
31
+ - [find()](#find) - List organizations
32
+ - [findOne()](#findone) - Get organization by ID
33
+ - [update()](#update) - Update organization
34
+ - [del()](#del) - Delete organization
35
+ - [addMember()](#addmember) - Add user to organization
36
+ - [listMembers()](#listmembers) - List organization members
37
+ - [delMember()](#delmember) - Remove user from organization
38
+ - [addIdentityProvider()](#addidentityprovider) - Link identity provider
39
+ - [listIdentityProviders()](#listidentityproviders) - List linked identity providers
40
+ - [delIdentityProvider()](#delidentityprovider) - Unlink identity provider
41
+
42
+ ---
43
+
44
+ ## create()
45
+
46
+ Create a new organization in the current realm.
47
+
48
+ **Syntax:**
49
+ ```javascript
50
+ const result = await KeycloakManager.organizations.create(organizationRepresentation)
51
+ ```
52
+
53
+ ### Parameters
54
+
55
+ #### organizationRepresentation (Object) ⚠️ Required
56
+
57
+ | Property | Type | Required | Description |
58
+ |----------|------|----------|-------------|
59
+ | `name` | string | ⚠️ Yes | Unique organization name |
60
+ | `displayName` | string | 📋 Optional | Human-readable display name |
61
+ | `url` | string | 📋 Optional | Organization website URL |
62
+ | `domains` | array | 📋 Optional | List of domain objects |
63
+ | `attributes` | object | 📋 Optional | Custom key-value attributes |
64
+
65
+ ### Returns
66
+
67
+ **Promise\<Object\>** - Created organization representation with `id`
68
+
69
+ ### Examples
70
+
71
+ #### Basic Organization
72
+
73
+ ```javascript
74
+ const org = await KeycloakManager.organizations.create({
75
+ name: 'acme-corp',
76
+ displayName: 'ACME Corporation',
77
+ url: 'https://www.acme.com'
78
+ });
79
+
80
+ console.log('Created organization:', org.id);
81
+ ```
82
+
83
+ #### With Domains and Attributes
84
+
85
+ ```javascript
86
+ const org = await KeycloakManager.organizations.create({
87
+ name: 'tech-startup',
88
+ displayName: 'Tech Startup Inc.',
89
+ url: 'https://techstartup.io',
90
+ domains: [
91
+ { name: 'techstartup.io', verified: true },
92
+ { name: 'staging.techstartup.io', verified: false }
93
+ ],
94
+ attributes: {
95
+ industry: ['Technology'],
96
+ country: ['USA'],
97
+ tier: ['Enterprise']
98
+ }
99
+ });
100
+
101
+ console.log('Organization with domains:', org);
102
+ ```
103
+
104
+ ---
105
+
106
+ ## find()
107
+
108
+ List all organizations in the current realm with optional filtering.
109
+
110
+ **Syntax:**
111
+ ```javascript
112
+ const organizations = await KeycloakManager.organizations.find(filter)
113
+ ```
114
+
115
+ ### Parameters
116
+
117
+ #### filter (Object) 📋 Optional
118
+
119
+ | Property | Type | Required | Description |
120
+ |----------|------|----------|-------------|
121
+ | `search` | string | 📋 Optional | Search organizations by name or display name |
122
+ | `first` | number | 📋 Optional | Index of first result (pagination) |
123
+ | `max` | number | 📋 Optional | Maximum number of results |
124
+ | `realm` | string | 📋 Optional | Override realm context |
125
+
126
+ ### Returns
127
+
128
+ **Promise\<Array\>** - Array of organization objects
129
+
130
+ ### Examples
131
+
132
+ #### List All Organizations
133
+
134
+ ```javascript
135
+ const orgs = await KeycloakManager.organizations.find();
136
+ console.log(`Found ${orgs.length} organizations`);
137
+
138
+ orgs.forEach(org => {
139
+ console.log(`- ${org.name}: ${org.displayName}`);
140
+ });
141
+ ```
142
+
143
+ #### Search with Pagination
144
+
145
+ ```javascript
146
+ const orgs = await KeycloakManager.organizations.find({
147
+ search: 'acme',
148
+ first: 0,
149
+ max: 10
150
+ });
151
+
152
+ console.log('First 10 organizations matching "acme":', orgs);
153
+ ```
154
+
155
+ ---
156
+
157
+ ## findOne()
158
+
159
+ Get a specific organization by ID.
160
+
161
+ **Syntax:**
162
+ ```javascript
163
+ const organization = await KeycloakManager.organizations.findOne(filter)
164
+ ```
165
+
166
+ ### Parameters
167
+
168
+ #### filter (Object) ⚠️ Required
169
+
170
+ | Property | Type | Required | Description |
171
+ |----------|------|----------|-------------|
172
+ | `id` | string | ⚠️ Yes | Organization UUID |
173
+ | `realm` | string | 📋 Optional | Override realm context |
174
+
175
+ ### Returns
176
+
177
+ **Promise\<Object\>** - Organization representation
178
+
179
+ ### Examples
180
+
181
+ ```javascript
182
+ const org = await KeycloakManager.organizations.findOne({
183
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
184
+ });
185
+
186
+ console.log('Organization:', org.name);
187
+ console.log('Display Name:', org.displayName);
188
+ console.log('URL:', org.url);
189
+ console.log('Attributes:', org.attributes);
190
+ ```
191
+
192
+ ---
193
+
194
+ ## update()
195
+
196
+ Update an existing organization. This performs a merge of the current organization data with the provided updates.
197
+
198
+ **Syntax:**
199
+ ```javascript
200
+ await KeycloakManager.organizations.update(filter, organizationRepresentation)
201
+ ```
202
+
203
+ ### Parameters
204
+
205
+ #### filter (Object) ⚠️ Required
206
+
207
+ | Property | Type | Required | Description |
208
+ |----------|------|----------|-------------|
209
+ | `id` | string | ⚠️ Yes | Organization UUID |
210
+
211
+ #### organizationRepresentation (Object) ⚠️ Required
212
+
213
+ Object containing fields to update (same structure as `create()`).
214
+
215
+ ### Returns
216
+
217
+ **Promise\<void\>** - Resolves when update completes
218
+
219
+ ### Examples
220
+
221
+ #### Update Display Name and URL
222
+
223
+ ```javascript
224
+ await KeycloakManager.organizations.update(
225
+ { id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479' },
226
+ {
227
+ displayName: 'ACME Corporation (Updated)',
228
+ url: 'https://www.acmecorp.com'
229
+ }
230
+ );
231
+
232
+ console.log('Organization updated');
233
+ ```
234
+
235
+ #### Update Attributes
236
+
237
+ ```javascript
238
+ await KeycloakManager.organizations.update(
239
+ { id: orgId },
240
+ {
241
+ attributes: {
242
+ tier: ['Premium'],
243
+ status: ['Active']
244
+ }
245
+ }
246
+ );
247
+ ```
248
+
249
+ ### Notes
250
+
251
+ - The update performs a MERGE operation - existing fields not mentioned are preserved.
252
+ - The `name` field, if provided, will be updated; otherwise the current name is kept.
253
+
254
+ ---
255
+
256
+ ## del()
257
+
258
+ Delete an organization.
259
+
260
+ **Syntax:**
261
+ ```javascript
262
+ await KeycloakManager.organizations.del(filter)
263
+ ```
264
+
265
+ ### Parameters
266
+
267
+ #### filter (Object) ⚠️ Required
268
+
269
+ | Property | Type | Required | Description |
270
+ |----------|------|----------|-------------|
271
+ | `id` | string | ⚠️ Yes | Organization UUID |
272
+
273
+ ### Returns
274
+
275
+ **Promise\<void\>** - Resolves when deletion completes
276
+
277
+ ### Examples
278
+
279
+ ```javascript
280
+ await KeycloakManager.organizations.del({
281
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
282
+ });
283
+
284
+ console.log('Organization deleted');
285
+ ```
286
+
287
+ ### Warning
288
+
289
+ Deleting an organization removes all associated memberships and identity provider links.
290
+
291
+ ---
292
+
293
+ ## addMember()
294
+
295
+ Add a user as a member of an organization.
296
+
297
+ **Syntax:**
298
+ ```javascript
299
+ await KeycloakManager.organizations.addMember(filter)
300
+ ```
301
+
302
+ ### Parameters
303
+
304
+ #### filter (Object) ⚠️ Required
305
+
306
+ | Property | Type | Required | Description |
307
+ |----------|------|----------|-------------|
308
+ | `id` | string | ⚠️ Yes | Organization UUID |
309
+ | `userId` | string | ⚠️ Yes | User UUID |
310
+
311
+ ### Returns
312
+
313
+ **Promise\<void\>** - Resolves when user is added
314
+
315
+ ### Examples
316
+
317
+ ```javascript
318
+ // First, find or create a user
319
+ const users = await KeycloakManager.users.find({ username: 'john.doe' });
320
+ const userId = users[0].id;
321
+
322
+ // Find organization
323
+ const orgs = await KeycloakManager.organizations.find({ search: 'acme' });
324
+ const orgId = orgs[0].id;
325
+
326
+ // Add user to organization
327
+ await KeycloakManager.organizations.addMember({
328
+ id: orgId,
329
+ userId: userId
330
+ });
331
+
332
+ console.log('User added to organization');
333
+ ```
334
+
335
+ ---
336
+
337
+ ## listMembers()
338
+
339
+ List all members (users) of an organization.
340
+
341
+ **Syntax:**
342
+ ```javascript
343
+ const members = await KeycloakManager.organizations.listMembers(filter)
344
+ ```
345
+
346
+ ### Parameters
347
+
348
+ #### filter (Object) ⚠️ Required
349
+
350
+ | Property | Type | Required | Description |
351
+ |----------|------|----------|-------------|
352
+ | `id` | string | ⚠️ Yes | Organization UUID |
353
+ | `first` | number | 📋 Optional | Index of first result (pagination) |
354
+ | `max` | number | 📋 Optional | Maximum number of results |
355
+
356
+ ### Returns
357
+
358
+ **Promise\<Array\>** - Array of user representations
359
+
360
+ ### Examples
361
+
362
+ ```javascript
363
+ const members = await KeycloakManager.organizations.listMembers({
364
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
365
+ max: 100
366
+ });
367
+
368
+ console.log(`Organization has ${members.length} members`);
369
+ members.forEach(user => {
370
+ console.log(`- ${user.username} (${user.email})`);
371
+ });
372
+ ```
373
+
374
+ ---
375
+
376
+ ## delMember()
377
+
378
+ Remove a user from an organization.
379
+
380
+ **Syntax:**
381
+ ```javascript
382
+ await KeycloakManager.organizations.delMember(filter)
383
+ ```
384
+
385
+ ### Parameters
386
+
387
+ #### filter (Object) ⚠️ Required
388
+
389
+ | Property | Type | Required | Description |
390
+ |----------|------|----------|-------------|
391
+ | `id` | string | ⚠️ Yes | Organization UUID |
392
+ | `userId` | string | ⚠️ Yes | User UUID |
393
+
394
+ ### Returns
395
+
396
+ **Promise\<void\>** - Resolves when user is removed
397
+
398
+ ### Examples
399
+
400
+ ```javascript
401
+ await KeycloakManager.organizations.delMember({
402
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
403
+ userId: 'a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d'
404
+ });
405
+
406
+ console.log('User removed from organization');
407
+ ```
408
+
409
+ ---
410
+
411
+ ## addIdentityProvider()
412
+
413
+ Link an identity provider to an organization for federated login.
414
+
415
+ **Syntax:**
416
+ ```javascript
417
+ await KeycloakManager.organizations.addIdentityProvider(filter)
418
+ ```
419
+
420
+ ### Parameters
421
+
422
+ #### filter (Object) ⚠️ Required
423
+
424
+ | Property | Type | Required | Description |
425
+ |----------|------|----------|-------------|
426
+ | `id` | string | ⚠️ Yes | Organization UUID |
427
+ | `alias` | string | ⚠️ Yes | Identity provider alias |
428
+
429
+ ### Returns
430
+
431
+ **Promise\<void\>** - Resolves when IdP is linked
432
+
433
+ ### Examples
434
+
435
+ ```javascript
436
+ // First, ensure identity provider exists
437
+ const idps = await KeycloakManager.identityProviders.find();
438
+ console.log('Available IdPs:', idps.map(i => i.alias));
439
+
440
+ // Link Google IdP to organization
441
+ await KeycloakManager.organizations.addIdentityProvider({
442
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
443
+ alias: 'google'
444
+ });
445
+
446
+ console.log('Identity provider linked to organization');
447
+ ```
448
+
449
+ ---
450
+
451
+ ## listIdentityProviders()
452
+
453
+ List all identity providers linked to an organization.
454
+
455
+ **Syntax:**
456
+ ```javascript
457
+ const idps = await KeycloakManager.organizations.listIdentityProviders(filter)
458
+ ```
459
+
460
+ ### Parameters
461
+
462
+ #### filter (Object) ⚠️ Required
463
+
464
+ | Property | Type | Required | Description |
465
+ |----------|------|----------|-------------|
466
+ | `id` | string | ⚠️ Yes | Organization UUID |
467
+
468
+ ### Returns
469
+
470
+ **Promise\<Array\>** - Array of identity provider representations
471
+
472
+ ### Examples
473
+
474
+ ```javascript
475
+ const idps = await KeycloakManager.organizations.listIdentityProviders({
476
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
477
+ });
478
+
479
+ console.log(`Organization has ${idps.length} linked identity providers`);
480
+ idps.forEach(idp => {
481
+ console.log(`- ${idp.alias} (${idp.providerId})`);
482
+ });
483
+ ```
484
+
485
+ ---
486
+
487
+ ## delIdentityProvider()
488
+
489
+ Unlink an identity provider from an organization.
490
+
491
+ **Syntax:**
492
+ ```javascript
493
+ await KeycloakManager.organizations.delIdentityProvider(filter)
494
+ ```
495
+
496
+ ### Parameters
497
+
498
+ #### filter (Object) ⚠️ Required
499
+
500
+ | Property | Type | Required | Description |
501
+ |----------|------|----------|-------------|
502
+ | `id` | string | ⚠️ Yes | Organization UUID |
503
+ | `alias` | string | ⚠️ Yes | Identity provider alias |
504
+
505
+ ### Returns
506
+
507
+ **Promise\<void\>** - Resolves when IdP is unlinked
508
+
509
+ ### Examples
510
+
511
+ ```javascript
512
+ await KeycloakManager.organizations.delIdentityProvider({
513
+ id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
514
+ alias: 'google'
515
+ });
516
+
517
+ console.log('Identity provider unlinked from organization');
518
+ ```
519
+
520
+ ---
521
+
522
+ ## Complete Workflow Example
523
+
524
+ ```javascript
525
+ const KeycloakManager = require('keycloak-api-manager');
526
+
527
+ async function organizationWorkflow() {
528
+ // Setup
529
+ await KeycloakManager.configure({
530
+ baseUrl: 'https://keycloak.example.com',
531
+ realmName: 'master',
532
+ username: 'admin',
533
+ password: 'admin',
534
+ grantType: 'password',
535
+ clientId: 'admin-cli'
536
+ });
537
+
538
+ KeycloakManager.setConfig({ realmName: 'my-app' });
539
+
540
+ try {
541
+ // 1. Create organization
542
+ const org = await KeycloakManager.organizations.create({
543
+ name: 'tech-corp',
544
+ displayName: 'Technology Corporation',
545
+ url: 'https://techcorp.io',
546
+ attributes: {
547
+ industry: ['Technology'],
548
+ size: ['Large']
549
+ }
550
+ });
551
+ console.log('✓ Created organization:', org.id);
552
+
553
+ // 2. Find user to add
554
+ const users = await KeycloakManager.users.find({
555
+ username: 'john.doe',
556
+ exact: true
557
+ });
558
+
559
+ if (users.length > 0) {
560
+ // 3. Add user as member
561
+ await KeycloakManager.organizations.addMember({
562
+ id: org.id,
563
+ userId: users[0].id
564
+ });
565
+ console.log('✓ Added user to organization');
566
+ }
567
+
568
+ // 4. Link identity provider
569
+ await KeycloakManager.organizations.addIdentityProvider({
570
+ id: org.id,
571
+ alias: 'google'
572
+ });
573
+ console.log('✓ Linked Google IdP');
574
+
575
+ // 5. List members
576
+ const members = await KeycloakManager.organizations.listMembers({
577
+ id: org.id
578
+ });
579
+ console.log(`✓ Organization has ${members.length} members`);
580
+
581
+ // 6. List identity providers
582
+ const idps = await KeycloakManager.organizations.listIdentityProviders({
583
+ id: org.id
584
+ });
585
+ console.log(`✓ Organization has ${idps.length} linked IdPs`);
586
+
587
+ // 7. Update organization
588
+ await KeycloakManager.organizations.update(
589
+ { id: org.id },
590
+ { displayName: 'Technology Corporation (Updated)' }
591
+ );
592
+ console.log('✓ Updated organization');
593
+
594
+ // 8. Cleanup (optional)
595
+ // await KeycloakManager.organizations.del({ id: org.id });
596
+ // console.log('✓ Deleted organization');
597
+
598
+ } catch (error) {
599
+ console.error('✗ Error:', error.message);
600
+ } finally {
601
+ KeycloakManager.stop();
602
+ }
603
+ }
604
+
605
+ organizationWorkflow();
606
+ ```
607
+
608
+ ---
609
+
610
+ ## See Also
611
+
612
+ - [API Reference](../api-reference.md) - Complete API index
613
+ - [Users API](users.md) - User management for adding members
614
+ - [Identity Providers API](identity-providers.md) - IdP configuration
615
+ - [Configuration](configuration.md) - Authentication setup