0
# SCIM User Provisioning
1
2
The SCIM API provides SCIM 2.0-compliant user provisioning for automated organization user management. All operations require an organization-scoped API key.
3
4
## Capabilities
5
6
### ScimClient
7
8
Client for SCIM 2.0 user provisioning operations.
9
10
```java { .api }
11
/**
12
* Get SCIM Service Provider Configuration
13
* Requires organization-scoped API key
14
*
15
* @param requestOptions Optional request configuration
16
*/
17
ServiceProviderConfig getServiceProviderConfig();
18
ServiceProviderConfig getServiceProviderConfig(RequestOptions requestOptions);
19
20
/**
21
* Get SCIM Resource Types
22
* Requires organization-scoped API key
23
*
24
* @param requestOptions Optional request configuration
25
*/
26
ResourceTypesResponse getResourceTypes();
27
ResourceTypesResponse getResourceTypes(RequestOptions requestOptions);
28
29
/**
30
* Get SCIM Schemas
31
* Requires organization-scoped API key
32
*
33
* @param requestOptions Optional request configuration
34
*/
35
SchemasResponse getSchemas();
36
SchemasResponse getSchemas(RequestOptions requestOptions);
37
38
/**
39
* List users in the organization
40
* Requires organization-scoped API key
41
*
42
* @param request Optional filters (filter query, startIndex, count)
43
* @param requestOptions Optional request configuration
44
*/
45
ScimUsersListResponse listUsers();
46
ScimUsersListResponse listUsers(ListUsersRequest request);
47
ScimUsersListResponse listUsers(ListUsersRequest request, RequestOptions requestOptions);
48
49
/**
50
* Create a new user in the organization
51
* Requires organization-scoped API key
52
*
53
* @param request User definition
54
* @param requestOptions Optional request configuration
55
*/
56
ScimUser createUser(CreateUserRequest request);
57
ScimUser createUser(CreateUserRequest request, RequestOptions requestOptions);
58
59
/**
60
* Get a specific user by ID
61
* Requires organization-scoped API key
62
*
63
* @param userId User ID
64
* @param requestOptions Optional request configuration
65
*/
66
ScimUser getUser(String userId);
67
ScimUser getUser(String userId, RequestOptions requestOptions);
68
69
/**
70
* Remove a user from the organization
71
* Note: Does not delete the user entity, only removes from organization
72
* Requires organization-scoped API key
73
*
74
* @param userId User ID
75
* @param requestOptions Optional request configuration
76
*/
77
EmptyResponse deleteUser(String userId);
78
EmptyResponse deleteUser(String userId, RequestOptions requestOptions);
79
```
80
81
**Usage Examples:**
82
83
```java
84
import com.langfuse.client.LangfuseClient;
85
import com.langfuse.client.resources.scim.types.*;
86
import java.util.List;
87
88
// Use organization-scoped API key
89
LangfuseClient client = LangfuseClient.builder()
90
.url("https://cloud.langfuse.com")
91
.credentials("org-pk-...", "org-sk-...")
92
.build();
93
94
// Get service provider config
95
ServiceProviderConfig config = client.scim().getServiceProviderConfig();
96
System.out.println("Documentation: " + config.getDocumentationUri());
97
98
// List all users
99
ScimUsersListResponse users = client.scim().listUsers();
100
for (ScimUser user : users.getResources()) {
101
System.out.println(user.getUserName() + " - " + user.getDisplayName());
102
}
103
104
// Filter users
105
ListUsersRequest filterRequest = ListUsersRequest.builder()
106
.filter("userName eq \"user@example.com\"")
107
.build();
108
109
ScimUsersListResponse filtered = client.scim().listUsers(filterRequest);
110
111
// Create a user
112
CreateUserRequest userRequest = CreateUserRequest.builder()
113
.userName("newuser@example.com")
114
.emails(List.of(
115
ScimEmail.builder()
116
.value("newuser@example.com")
117
.type("work")
118
.primary(true)
119
.build()
120
))
121
.name(ScimName.builder()
122
.givenName("John")
123
.familyName("Doe")
124
.formatted("John Doe")
125
.build())
126
.displayName("John Doe")
127
.active(true)
128
.build();
129
130
ScimUser newUser = client.scim().createUser(userRequest);
131
System.out.println("Created user: " + newUser.getId());
132
133
// Get a specific user
134
ScimUser user = client.scim().getUser(newUser.getId());
135
136
// Remove user from organization
137
EmptyResponse deleteResp = client.scim().deleteUser(newUser.getId());
138
```
139
140
## Request Types
141
142
### ListUsersRequest
143
144
```java { .api }
145
/**
146
* Request parameters for listing users
147
*/
148
public final class ListUsersRequest {
149
Optional<String> getFilter(); // SCIM filter query
150
Optional<Integer> getStartIndex(); // 1-based index (default: 1)
151
Optional<Integer> getCount(); // Items per page (default: 100)
152
153
static Builder builder();
154
}
155
```
156
157
### CreateUserRequest
158
159
```java { .api }
160
/**
161
* Request for creating a user
162
*/
163
public final class CreateUserRequest {
164
String getUserName(); // Username (usually email)
165
List<ScimEmail> getEmails(); // Email addresses
166
Optional<ScimName> getName(); // Name components
167
Optional<String> getDisplayName(); // Display name
168
Optional<Boolean> getActive(); // Active status
169
170
static Builder builder();
171
}
172
```
173
174
## Response Types
175
176
### ServiceProviderConfig
177
178
```java { .api }
179
/**
180
* SCIM Service Provider Configuration
181
*/
182
public final class ServiceProviderConfig {
183
String getDocumentationUri();
184
ScimFeatureSupport getPatch();
185
BulkConfig getBulk();
186
FilterConfig getFilter();
187
ScimFeatureSupport getChangePassword();
188
ScimFeatureSupport getSort();
189
ScimFeatureSupport getEtag();
190
List<AuthenticationScheme> getAuthenticationSchemes();
191
192
static Builder builder();
193
}
194
```
195
196
### ResourceTypesResponse
197
198
```java { .api }
199
/**
200
* SCIM Resource Types
201
*/
202
public final class ResourceTypesResponse {
203
List<ResourceType> getResources();
204
205
static Builder builder();
206
}
207
```
208
209
### SchemasResponse
210
211
```java { .api }
212
/**
213
* SCIM Schemas
214
*/
215
public final class SchemasResponse {
216
List<SchemaResource> getResources();
217
218
static Builder builder();
219
}
220
```
221
222
### ScimUsersListResponse
223
224
```java { .api }
225
/**
226
* Paginated list of SCIM users
227
*/
228
public final class ScimUsersListResponse {
229
List<ScimUser> getResources();
230
int getTotalResults();
231
int getStartIndex();
232
int getItemsPerPage();
233
234
static Builder builder();
235
}
236
```
237
238
### ScimUser
239
240
```java { .api }
241
/**
242
* SCIM user resource
243
*/
244
public final class ScimUser {
245
String getId();
246
String getUserName();
247
List<ScimEmail> getEmails();
248
Optional<ScimName> getName();
249
Optional<String> getDisplayName();
250
Optional<Boolean> getActive();
251
Optional<UserMeta> getMeta();
252
253
static Builder builder();
254
}
255
```
256
257
### EmptyResponse
258
259
```java { .api }
260
/**
261
* Empty response for delete operations
262
*/
263
public final class EmptyResponse {
264
static Builder builder();
265
}
266
```
267
268
## Supporting Types
269
270
### ScimEmail
271
272
```java { .api }
273
/**
274
* Email address with type and primary flag
275
*/
276
public final class ScimEmail {
277
String getValue(); // Email address
278
Optional<String> getType(); // "work", "home", etc.
279
Optional<Boolean> getPrimary(); // Primary email flag
280
281
static Builder builder();
282
}
283
```
284
285
### ScimName
286
287
```java { .api }
288
/**
289
* User name components
290
*/
291
public final class ScimName {
292
Optional<String> getFormatted(); // Full formatted name
293
Optional<String> getFamilyName(); // Last name
294
Optional<String> getGivenName(); // First name
295
296
static Builder builder();
297
}
298
```
299
300
### UserMeta
301
302
```java { .api }
303
/**
304
* User metadata
305
*/
306
public final class UserMeta {
307
String getResourceType();
308
Optional<String> getCreated(); // ISO 8601 timestamp
309
Optional<String> getLastModified(); // ISO 8601 timestamp
310
311
static Builder builder();
312
}
313
```
314
315
### ScimFeatureSupport
316
317
```java { .api }
318
/**
319
* Feature support indicator
320
*/
321
public final class ScimFeatureSupport {
322
boolean getSupported();
323
324
static Builder builder();
325
}
326
```
327
328
### BulkConfig
329
330
```java { .api }
331
/**
332
* Bulk operation configuration
333
*/
334
public final class BulkConfig {
335
boolean getSupported();
336
int getMaxOperations();
337
int getMaxPayloadSize();
338
339
static Builder builder();
340
}
341
```
342
343
### FilterConfig
344
345
```java { .api }
346
/**
347
* Filter configuration
348
*/
349
public final class FilterConfig {
350
boolean getSupported();
351
int getMaxResults();
352
353
static Builder builder();
354
}
355
```
356
357
### AuthenticationScheme
358
359
```java { .api }
360
/**
361
* Authentication scheme details
362
*/
363
public final class AuthenticationScheme {
364
String getType();
365
String getName();
366
String getDescription();
367
Optional<String> getDocumentationUri();
368
369
static Builder builder();
370
}
371
```
372
373
### ResourceType
374
375
```java { .api }
376
/**
377
* SCIM resource type definition
378
*/
379
public final class ResourceType {
380
String getId();
381
String getName();
382
String getDescription();
383
String getEndpoint();
384
String getSchema();
385
Optional<List<SchemaExtension>> getSchemaExtensions();
386
387
static Builder builder();
388
}
389
```
390
391
### SchemaResource
392
393
```java { .api }
394
/**
395
* SCIM schema resource definition
396
*/
397
public final class SchemaResource {
398
String getId();
399
String getName();
400
String getDescription();
401
Object getAttributes(); // Schema attributes definition
402
403
static Builder builder();
404
}
405
```
406
407
## Complete SCIM Provisioning Example
408
409
```java
410
import com.langfuse.client.LangfuseClient;
411
import com.langfuse.client.resources.scim.types.*;
412
import java.util.List;
413
414
public class ScimProvisioningExample {
415
public static void main(String[] args) {
416
// Use organization-scoped API key
417
LangfuseClient client = LangfuseClient.builder()
418
.url("https://cloud.langfuse.com")
419
.credentials("org-pk-...", "org-sk-...")
420
.build();
421
422
// 1. Get SCIM service provider config
423
ServiceProviderConfig config = client.scim().getServiceProviderConfig();
424
System.out.println("SCIM documentation: " + config.getDocumentationUri());
425
System.out.println("Patch supported: " + config.getPatch().getSupported());
426
System.out.println("Bulk supported: " + config.getBulk().getSupported());
427
428
// 2. List existing users
429
ScimUsersListResponse users = client.scim().listUsers();
430
System.out.println("\nExisting users: " + users.getTotalResults());
431
432
for (ScimUser user : users.getResources()) {
433
System.out.println(" " + user.getUserName() +
434
" - Active: " + user.getActive().orElse(true));
435
}
436
437
// 3. Create new users from HR system
438
String[] newEmployees = {
439
"alice@example.com",
440
"bob@example.com",
441
"charlie@example.com"
442
};
443
444
for (String email : newEmployees) {
445
String[] parts = email.split("@")[0].split("\\.");
446
String firstName = capitalize(parts[0]);
447
String lastName = parts.length > 1 ? capitalize(parts[1]) : "";
448
449
CreateUserRequest userRequest = CreateUserRequest.builder()
450
.userName(email)
451
.emails(List.of(
452
ScimEmail.builder()
453
.value(email)
454
.type("work")
455
.primary(true)
456
.build()
457
))
458
.name(ScimName.builder()
459
.givenName(firstName)
460
.familyName(lastName)
461
.formatted(firstName + (lastName.isEmpty() ? "" : " " + lastName))
462
.build())
463
.displayName(firstName + (lastName.isEmpty() ? "" : " " + lastName))
464
.active(true)
465
.build();
466
467
try {
468
ScimUser created = client.scim().createUser(userRequest);
469
System.out.println("Created user: " + created.getUserName() +
470
" (ID: " + created.getId() + ")");
471
} catch (Exception e) {
472
System.err.println("Failed to create " + email + ": " + e.getMessage());
473
}
474
}
475
476
// 4. Filter for specific user
477
ListUsersRequest filterRequest = ListUsersRequest.builder()
478
.filter("userName eq \"alice@example.com\"")
479
.build();
480
481
ScimUsersListResponse filtered = client.scim().listUsers(filterRequest);
482
if (!filtered.getResources().isEmpty()) {
483
ScimUser alice = filtered.getResources().get(0);
484
System.out.println("\nFound user: " + alice.getDisplayName());
485
}
486
487
// 5. Paginate through large user list
488
int startIndex = 1;
489
int pageSize = 50;
490
boolean hasMore = true;
491
492
while (hasMore) {
493
ListUsersRequest pageRequest = ListUsersRequest.builder()
494
.startIndex(startIndex)
495
.count(pageSize)
496
.build();
497
498
ScimUsersListResponse page = client.scim().listUsers(pageRequest);
499
500
System.out.println("\nPage starting at " + startIndex +
501
": " + page.getResources().size() + " users");
502
503
for (ScimUser user : page.getResources()) {
504
System.out.println(" " + user.getUserName());
505
}
506
507
hasMore = startIndex + pageSize <= page.getTotalResults();
508
startIndex += pageSize;
509
}
510
511
// 6. Deactivate users (remove from organization)
512
// Note: This doesn't delete the user, just removes from organization
513
ListUsersRequest inactiveRequest = ListUsersRequest.builder()
514
.filter("active eq false")
515
.build();
516
517
ScimUsersListResponse inactive = client.scim().listUsers(inactiveRequest);
518
519
for (ScimUser user : inactive.getResources()) {
520
client.scim().deleteUser(user.getId());
521
System.out.println("Removed user from organization: " + user.getUserName());
522
}
523
}
524
525
private static String capitalize(String str) {
526
if (str == null || str.isEmpty()) return str;
527
return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
528
}
529
}
530
```
531
532
## SCIM Filter Examples
533
534
### Filter by Username
535
536
```java
537
ListUsersRequest request = ListUsersRequest.builder()
538
.filter("userName eq \"user@example.com\"")
539
.build();
540
```
541
542
### Filter by Active Status
543
544
```java
545
ListUsersRequest request = ListUsersRequest.builder()
546
.filter("active eq true")
547
.build();
548
```
549
550
### Filter by Email
551
552
```java
553
ListUsersRequest request = ListUsersRequest.builder()
554
.filter("emails.value eq \"user@example.com\"")
555
.build();
556
```
557
558
### Complex Filters
559
560
```java
561
// AND operator
562
String filter = "active eq true and userName co \"@example.com\"";
563
564
// OR operator
565
String filter = "userName eq \"user1@example.com\" or userName eq \"user2@example.com\"";
566
567
ListUsersRequest request = ListUsersRequest.builder()
568
.filter(filter)
569
.build();
570
```
571
572
## Best Practices
573
574
1. **Organization Keys Required**: All SCIM operations require organization-scoped API keys
575
2. **Pagination**: Use pagination for large user lists
576
3. **Filter Queries**: Use SCIM filter syntax for efficient queries
577
4. **Bulk Operations**: Check bulk support in service provider config
578
5. **Error Handling**: Handle duplicate username errors gracefully
579
6. **Active Status**: Track user active status instead of deleting
580
7. **Email Uniqueness**: Usernames and primary emails must be unique
581
8. **Integration Testing**: Test SCIM flows in development environment first
582
583
## SCIM 2.0 Compliance
584
585
Langfuse implements SCIM 2.0 core specification:
586
- Service Provider Configuration endpoint
587
- Resource Types endpoint
588
- Schemas endpoint
589
- User resource CRUD operations
590
- Filtering support
591
- Pagination support
592
593
## Related Documentation
594
595
- [Projects and Organizations](./projects-organizations.md) - Organization management
596
- [Client Configuration](./client-configuration.md) - API key configuration
597