@better-auth/scim 1.5.0-beta.13 → 1.5.0-beta.15

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.
@@ -1,19 +1,19 @@
1
1
 
2
- > @better-auth/scim@1.5.0-beta.13 build /home/runner/work/better-auth/better-auth/packages/scim
2
+ > @better-auth/scim@1.5.0-beta.15 build /home/runner/work/better-auth/better-auth/packages/scim
3
3
  > tsdown
4
4
 
5
- ℹ tsdown v0.20.1 powered by rolldown v1.0.0-rc.1
5
+ ℹ tsdown v0.20.3 powered by rolldown v1.0.0-rc.3
6
6
  ℹ config file: /home/runner/work/better-auth/better-auth/packages/scim/tsdown.config.ts
7
7
  ℹ entry: src/index.ts, src/client.ts
8
8
  ℹ tsconfig: tsconfig.json
9
9
  ℹ Build start
10
- ℹ dist/index.mjs  39.71 kB │ gzip: 8.09 kB
10
+ ℹ dist/index.mjs  45.12 kB │ gzip: 8.92 kB
11
11
  ℹ dist/client.mjs  0.19 kB │ gzip: 0.17 kB
12
- ℹ dist/index.mjs.map  78.91 kB │ gzip: 15.31 kB
12
+ ℹ dist/index.mjs.map  90.39 kB │ gzip: 17.19 kB
13
13
  ℹ dist/client.mjs.map  0.46 kB │ gzip: 0.30 kB
14
- ℹ dist/index.d.mts 108.99 kB │ gzip: 4.52 kB
14
+ ℹ dist/index.d.mts 115.17 kB │ gzip: 4.89 kB
15
15
  ℹ dist/client.d.mts  0.24 kB │ gzip: 0.20 kB
16
- ℹ 6 files, total: 228.50 kB
16
+ ℹ 6 files, total: 251.57 kB
17
17
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
18
18
 
19
- ✔ Build complete in 8905ms
19
+ ✔ Build complete in 10301ms
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import * as better_auth0 from "better-auth";
2
2
  import { User } from "better-auth";
3
3
  import * as better_call0 from "better-call";
4
4
  import { Member } from "better-auth/plugins";
5
- import * as zod0 from "zod";
5
+ import * as zod from "zod";
6
6
 
7
7
  //#region src/types.d.ts
8
8
  interface SCIMProvider {
@@ -10,6 +10,7 @@ interface SCIMProvider {
10
10
  providerId: string;
11
11
  scimToken: string;
12
12
  organizationId?: string;
13
+ userId?: string;
13
14
  }
14
15
  type SCIMName = {
15
16
  formatted?: string;
@@ -21,6 +22,13 @@ type SCIMEmail = {
21
22
  primary?: boolean;
22
23
  };
23
24
  type SCIMOptions = {
25
+ /**
26
+ * SCIM provider ownership configuration. When enabled, each provider
27
+ * connection is linked to the user who generated its token
28
+ */
29
+ providerOwnership?: {
30
+ enabled: boolean;
31
+ };
24
32
  /**
25
33
  * Default list of SCIM providers for testing
26
34
  * These will take precedence over the database when present
@@ -79,9 +87,9 @@ declare const scim: (options?: SCIMOptions) => {
79
87
  endpoints: {
80
88
  generateSCIMToken: better_call0.StrictEndpoint<"/scim/generate-token", {
81
89
  method: "POST";
82
- body: zod0.ZodObject<{
83
- providerId: zod0.ZodString;
84
- organizationId: zod0.ZodOptional<zod0.ZodString>;
90
+ body: zod.ZodObject<{
91
+ providerId: zod.ZodString;
92
+ organizationId: zod.ZodOptional<zod.ZodString>;
85
93
  }, better_auth0.$strip>;
86
94
  metadata: {
87
95
  openapi: {
@@ -133,6 +141,208 @@ declare const scim: (options?: SCIMOptions) => {
133
141
  }, {
134
142
  scimToken: string;
135
143
  }>;
144
+ listSCIMProviderConnections: better_call0.StrictEndpoint<"/scim/list-provider-connections", {
145
+ method: "GET";
146
+ use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
147
+ session: {
148
+ session: Record<string, any> & {
149
+ id: string;
150
+ createdAt: Date;
151
+ updatedAt: Date;
152
+ userId: string;
153
+ expiresAt: Date;
154
+ token: string;
155
+ ipAddress?: string | null | undefined;
156
+ userAgent?: string | null | undefined;
157
+ };
158
+ user: Record<string, any> & {
159
+ id: string;
160
+ createdAt: Date;
161
+ updatedAt: Date;
162
+ email: string;
163
+ emailVerified: boolean;
164
+ name: string;
165
+ image?: string | null | undefined;
166
+ };
167
+ };
168
+ }>)[];
169
+ metadata: {
170
+ openapi: {
171
+ operationId: string;
172
+ summary: string;
173
+ description: string;
174
+ responses: {
175
+ "200": {
176
+ description: string;
177
+ content: {
178
+ "application/json": {
179
+ schema: {
180
+ type: "object";
181
+ properties: {
182
+ providers: {
183
+ type: string;
184
+ items: {
185
+ type: string;
186
+ properties: {
187
+ id: {
188
+ type: string;
189
+ };
190
+ providerId: {
191
+ type: string;
192
+ };
193
+ organizationId: {
194
+ type: string;
195
+ nullable: boolean;
196
+ };
197
+ };
198
+ };
199
+ };
200
+ };
201
+ };
202
+ };
203
+ };
204
+ };
205
+ };
206
+ };
207
+ };
208
+ }, {
209
+ providers: {
210
+ id: string;
211
+ providerId: string;
212
+ organizationId: string | null;
213
+ }[];
214
+ }>;
215
+ getSCIMProviderConnection: better_call0.StrictEndpoint<"/scim/get-provider-connection", {
216
+ method: "GET";
217
+ use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
218
+ session: {
219
+ session: Record<string, any> & {
220
+ id: string;
221
+ createdAt: Date;
222
+ updatedAt: Date;
223
+ userId: string;
224
+ expiresAt: Date;
225
+ token: string;
226
+ ipAddress?: string | null | undefined;
227
+ userAgent?: string | null | undefined;
228
+ };
229
+ user: Record<string, any> & {
230
+ id: string;
231
+ createdAt: Date;
232
+ updatedAt: Date;
233
+ email: string;
234
+ emailVerified: boolean;
235
+ name: string;
236
+ image?: string | null | undefined;
237
+ };
238
+ };
239
+ }>)[];
240
+ query: zod.ZodObject<{
241
+ providerId: zod.ZodString;
242
+ }, better_auth0.$strip>;
243
+ metadata: {
244
+ openapi: {
245
+ operationId: string;
246
+ summary: string;
247
+ description: string;
248
+ responses: {
249
+ "200": {
250
+ description: string;
251
+ content: {
252
+ "application/json": {
253
+ schema: {
254
+ type: "object";
255
+ properties: {
256
+ id: {
257
+ type: string;
258
+ };
259
+ providerId: {
260
+ type: string;
261
+ };
262
+ organizationId: {
263
+ type: string;
264
+ nullable: boolean;
265
+ };
266
+ };
267
+ };
268
+ };
269
+ };
270
+ };
271
+ "404": {
272
+ description: string;
273
+ };
274
+ "403": {
275
+ description: string;
276
+ };
277
+ };
278
+ };
279
+ };
280
+ }, {
281
+ id: string;
282
+ providerId: string;
283
+ organizationId: string | null;
284
+ }>;
285
+ deleteSCIMProviderConnection: better_call0.StrictEndpoint<"/scim/delete-provider-connection", {
286
+ method: "POST";
287
+ use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
288
+ session: {
289
+ session: Record<string, any> & {
290
+ id: string;
291
+ createdAt: Date;
292
+ updatedAt: Date;
293
+ userId: string;
294
+ expiresAt: Date;
295
+ token: string;
296
+ ipAddress?: string | null | undefined;
297
+ userAgent?: string | null | undefined;
298
+ };
299
+ user: Record<string, any> & {
300
+ id: string;
301
+ createdAt: Date;
302
+ updatedAt: Date;
303
+ email: string;
304
+ emailVerified: boolean;
305
+ name: string;
306
+ image?: string | null | undefined;
307
+ };
308
+ };
309
+ }>)[];
310
+ body: zod.ZodObject<{
311
+ providerId: zod.ZodString;
312
+ }, better_auth0.$strip>;
313
+ metadata: {
314
+ openapi: {
315
+ operationId: string;
316
+ summary: string;
317
+ description: string;
318
+ responses: {
319
+ "200": {
320
+ description: string;
321
+ content: {
322
+ "application/json": {
323
+ schema: {
324
+ type: "object";
325
+ properties: {
326
+ success: {
327
+ type: string;
328
+ };
329
+ };
330
+ };
331
+ };
332
+ };
333
+ };
334
+ "404": {
335
+ description: string;
336
+ };
337
+ "403": {
338
+ description: string;
339
+ };
340
+ };
341
+ };
342
+ };
343
+ }, {
344
+ success: boolean;
345
+ }>;
136
346
  getSCIMUser: better_call0.StrictEndpoint<"/scim/v2/Users/:userId", {
137
347
  method: "GET";
138
348
  metadata: {
@@ -411,17 +621,17 @@ declare const scim: (options?: SCIMOptions) => {
411
621
  }>;
412
622
  createSCIMUser: better_call0.StrictEndpoint<"/scim/v2/Users", {
413
623
  method: "POST";
414
- body: zod0.ZodObject<{
415
- userName: zod0.ZodString;
416
- externalId: zod0.ZodOptional<zod0.ZodString>;
417
- name: zod0.ZodOptional<zod0.ZodObject<{
418
- formatted: zod0.ZodOptional<zod0.ZodString>;
419
- givenName: zod0.ZodOptional<zod0.ZodString>;
420
- familyName: zod0.ZodOptional<zod0.ZodString>;
624
+ body: zod.ZodObject<{
625
+ userName: zod.ZodString;
626
+ externalId: zod.ZodOptional<zod.ZodString>;
627
+ name: zod.ZodOptional<zod.ZodObject<{
628
+ formatted: zod.ZodOptional<zod.ZodString>;
629
+ givenName: zod.ZodOptional<zod.ZodString>;
630
+ familyName: zod.ZodOptional<zod.ZodString>;
421
631
  }, better_auth0.$strip>>;
422
- emails: zod0.ZodOptional<zod0.ZodArray<zod0.ZodObject<{
423
- value: zod0.ZodEmail;
424
- primary: zod0.ZodOptional<zod0.ZodBoolean>;
632
+ emails: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
633
+ value: zod.ZodEmail;
634
+ primary: zod.ZodOptional<zod.ZodBoolean>;
425
635
  }, better_auth0.$strip>>>;
426
636
  }, better_auth0.$strip>;
427
637
  metadata: {
@@ -700,16 +910,16 @@ declare const scim: (options?: SCIMOptions) => {
700
910
  }>;
701
911
  patchSCIMUser: better_call0.StrictEndpoint<"/scim/v2/Users/:userId", {
702
912
  method: "PATCH";
703
- body: zod0.ZodObject<{
704
- schemas: zod0.ZodArray<zod0.ZodString>;
705
- Operations: zod0.ZodArray<zod0.ZodObject<{
706
- op: zod0.ZodPipe<zod0.ZodDefault<zod0.ZodString>, zod0.ZodEnum<{
913
+ body: zod.ZodObject<{
914
+ schemas: zod.ZodArray<zod.ZodString>;
915
+ Operations: zod.ZodArray<zod.ZodObject<{
916
+ op: zod.ZodPipe<zod.ZodDefault<zod.ZodString>, zod.ZodEnum<{
707
917
  add: "add";
708
918
  remove: "remove";
709
919
  replace: "replace";
710
920
  }>>;
711
- path: zod0.ZodOptional<zod0.ZodString>;
712
- value: zod0.ZodAny;
921
+ path: zod.ZodOptional<zod.ZodString>;
922
+ value: zod.ZodAny;
713
923
  }, better_auth0.$strip>>;
714
924
  }, better_auth0.$strip>;
715
925
  metadata: {
@@ -1076,17 +1286,17 @@ declare const scim: (options?: SCIMOptions) => {
1076
1286
  }, void>;
1077
1287
  updateSCIMUser: better_call0.StrictEndpoint<"/scim/v2/Users/:userId", {
1078
1288
  method: "PUT";
1079
- body: zod0.ZodObject<{
1080
- userName: zod0.ZodString;
1081
- externalId: zod0.ZodOptional<zod0.ZodString>;
1082
- name: zod0.ZodOptional<zod0.ZodObject<{
1083
- formatted: zod0.ZodOptional<zod0.ZodString>;
1084
- givenName: zod0.ZodOptional<zod0.ZodString>;
1085
- familyName: zod0.ZodOptional<zod0.ZodString>;
1289
+ body: zod.ZodObject<{
1290
+ userName: zod.ZodString;
1291
+ externalId: zod.ZodOptional<zod.ZodString>;
1292
+ name: zod.ZodOptional<zod.ZodObject<{
1293
+ formatted: zod.ZodOptional<zod.ZodString>;
1294
+ givenName: zod.ZodOptional<zod.ZodString>;
1295
+ familyName: zod.ZodOptional<zod.ZodString>;
1086
1296
  }, better_auth0.$strip>>;
1087
- emails: zod0.ZodOptional<zod0.ZodArray<zod0.ZodObject<{
1088
- value: zod0.ZodEmail;
1089
- primary: zod0.ZodOptional<zod0.ZodBoolean>;
1297
+ emails: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
1298
+ value: zod.ZodEmail;
1299
+ primary: zod.ZodOptional<zod.ZodBoolean>;
1090
1300
  }, better_auth0.$strip>>>;
1091
1301
  }, better_auth0.$strip>;
1092
1302
  metadata: {
@@ -1365,8 +1575,8 @@ declare const scim: (options?: SCIMOptions) => {
1365
1575
  }>;
1366
1576
  listSCIMUsers: better_call0.StrictEndpoint<"/scim/v2/Users", {
1367
1577
  method: "GET";
1368
- query: zod0.ZodOptional<zod0.ZodObject<{
1369
- filter: zod0.ZodOptional<zod0.ZodString>;
1578
+ query: zod.ZodOptional<zod.ZodObject<{
1579
+ filter: zod.ZodOptional<zod.ZodString>;
1370
1580
  }, better_auth0.$strip>>;
1371
1581
  metadata: {
1372
1582
  allowedMediaTypes: string[];
@@ -3205,6 +3415,10 @@ declare const scim: (options?: SCIMOptions) => {
3205
3415
  schema: {
3206
3416
  scimProvider: {
3207
3417
  fields: {
3418
+ userId?: {
3419
+ type: "string";
3420
+ required: false;
3421
+ } | undefined;
3208
3422
  providerId: {
3209
3423
  type: "string";
3210
3424
  required: true;
package/dist/index.mjs CHANGED
@@ -618,6 +618,55 @@ const generateSCIMTokenBodySchema = z.object({
618
618
  providerId: z.string().meta({ description: "Unique provider identifier" }),
619
619
  organizationId: z.string().optional().meta({ description: "Optional organization id" })
620
620
  });
621
+ const getSCIMProviderConnectionQuerySchema = z.object({ providerId: z.string() });
622
+ const deleteSCIMProviderConnectionBodySchema = z.object({ providerId: z.string() });
623
+ async function getSCIMUserOrgIds(ctx, userId) {
624
+ const members = await ctx.context.adapter.findMany({
625
+ model: "member",
626
+ where: [{
627
+ field: "userId",
628
+ value: userId
629
+ }]
630
+ });
631
+ return new Set(members.map((m) => m.organizationId));
632
+ }
633
+ function normalizeSCIMProvider(provider) {
634
+ return {
635
+ id: provider.id,
636
+ providerId: provider.providerId,
637
+ organizationId: provider.organizationId ?? null
638
+ };
639
+ }
640
+ async function findOrganizationMember(ctx, userId, organizationId) {
641
+ return ctx.context.adapter.findOne({
642
+ model: "member",
643
+ where: [{
644
+ field: "userId",
645
+ value: userId
646
+ }, {
647
+ field: "organizationId",
648
+ value: organizationId
649
+ }]
650
+ });
651
+ }
652
+ async function assertSCIMProviderAccess(ctx, userId, provider) {
653
+ if (provider.organizationId) {
654
+ if (!ctx.context.hasPlugin("organization")) throw new APIError("FORBIDDEN", { message: "Organization plugin is required to access this SCIM provider" });
655
+ if (!await findOrganizationMember(ctx, userId, provider.organizationId)) throw new APIError("FORBIDDEN", { message: "You must be a member of the organization to access this provider" });
656
+ } else if (provider.userId && provider.userId !== userId) throw new APIError("FORBIDDEN", { message: "You must be the owner to access this provider" });
657
+ }
658
+ async function checkSCIMProviderAccess(ctx, userId, providerId) {
659
+ const provider = await ctx.context.adapter.findOne({
660
+ model: "scimProvider",
661
+ where: [{
662
+ field: "providerId",
663
+ value: providerId
664
+ }]
665
+ });
666
+ if (!provider) throw new APIError("NOT_FOUND", { message: "SCIM provider not found" });
667
+ await assertSCIMProviderAccess(ctx, userId, provider);
668
+ return provider;
669
+ }
621
670
  const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
622
671
  method: "POST",
623
672
  body: generateSCIMTokenBodySchema,
@@ -643,16 +692,7 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
643
692
  if (organizationId && !ctx.context.hasPlugin("organization")) throw new APIError("BAD_REQUEST", { message: "Restricting a token to an organization requires the organization plugin" });
644
693
  let member = null;
645
694
  if (organizationId) {
646
- member = await ctx.context.adapter.findOne({
647
- model: "member",
648
- where: [{
649
- field: "userId",
650
- value: user.id
651
- }, {
652
- field: "organizationId",
653
- value: organizationId
654
- }]
655
- });
695
+ member = await findOrganizationMember(ctx, user.id, organizationId);
656
696
  if (!member) throw new APIError("FORBIDDEN", { message: "You are not a member of the organization" });
657
697
  }
658
698
  const scimProvider = await ctx.context.adapter.findOne({
@@ -665,13 +705,16 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
665
705
  value: organizationId
666
706
  }] : []]
667
707
  });
668
- if (scimProvider) await ctx.context.adapter.delete({
669
- model: "scimProvider",
670
- where: [{
671
- field: "id",
672
- value: scimProvider.id
673
- }]
674
- });
708
+ if (scimProvider) {
709
+ await assertSCIMProviderAccess(ctx, user.id, scimProvider);
710
+ await ctx.context.adapter.delete({
711
+ model: "scimProvider",
712
+ where: [{
713
+ field: "id",
714
+ value: scimProvider.id
715
+ }]
716
+ });
717
+ }
675
718
  const baseToken = generateRandomString(24);
676
719
  const scimToken = base64Url.encode(`${baseToken}:${providerId}${organizationId ? `:${organizationId}` : ""}`);
677
720
  if (opts.beforeSCIMTokenGenerated) await opts.beforeSCIMTokenGenerated({
@@ -684,7 +727,8 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
684
727
  data: {
685
728
  providerId,
686
729
  organizationId,
687
- scimToken: await storeSCIMToken(ctx, opts, baseToken)
730
+ scimToken: await storeSCIMToken(ctx, opts, baseToken),
731
+ ...opts.providerOwnership?.enabled ? { userId: user.id } : {}
688
732
  }
689
733
  });
690
734
  if (opts.afterSCIMTokenGenerated) await opts.afterSCIMTokenGenerated({
@@ -696,6 +740,110 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
696
740
  ctx.setStatus(201);
697
741
  return ctx.json({ scimToken });
698
742
  });
743
+ const listSCIMProviderConnections = () => createAuthEndpoint("/scim/list-provider-connections", {
744
+ method: "GET",
745
+ use: [sessionMiddleware],
746
+ metadata: { openapi: {
747
+ operationId: "listSCIMProviderConnections",
748
+ summary: "List SCIM providers",
749
+ description: "Returns SCIM providers for organizations the user is a member of.",
750
+ responses: { "200": {
751
+ description: "List of SCIM providers",
752
+ content: { "application/json": { schema: {
753
+ type: "object",
754
+ properties: { providers: {
755
+ type: "array",
756
+ items: {
757
+ type: "object",
758
+ properties: {
759
+ id: { type: "string" },
760
+ providerId: { type: "string" },
761
+ organizationId: {
762
+ type: "string",
763
+ nullable: true
764
+ }
765
+ }
766
+ }
767
+ } }
768
+ } } }
769
+ } }
770
+ } }
771
+ }, async (ctx) => {
772
+ const userId = ctx.context.session.user.id;
773
+ const userOrgIds = ctx.context.hasPlugin("organization") ? await getSCIMUserOrgIds(ctx, userId) : /* @__PURE__ */ new Set();
774
+ const providers = (await ctx.context.adapter.findMany({ model: "scimProvider" })).filter((p) => {
775
+ if (p.organizationId) return userOrgIds.has(p.organizationId);
776
+ if (p.userId === userId) return true;
777
+ return !p.userId;
778
+ }).map((p) => normalizeSCIMProvider(p));
779
+ return ctx.json({ providers });
780
+ });
781
+ const getSCIMProviderConnection = () => createAuthEndpoint("/scim/get-provider-connection", {
782
+ method: "GET",
783
+ use: [sessionMiddleware],
784
+ query: getSCIMProviderConnectionQuerySchema,
785
+ metadata: { openapi: {
786
+ operationId: "getSCIMProviderConnection",
787
+ summary: "Get SCIM provider details",
788
+ description: "Returns details for a specific SCIM provider",
789
+ responses: {
790
+ "200": {
791
+ description: "SCIM provider details",
792
+ content: { "application/json": { schema: {
793
+ type: "object",
794
+ properties: {
795
+ id: { type: "string" },
796
+ providerId: { type: "string" },
797
+ organizationId: {
798
+ type: "string",
799
+ nullable: true
800
+ }
801
+ }
802
+ } } }
803
+ },
804
+ "404": { description: "Provider not found" },
805
+ "403": { description: "Access denied" }
806
+ }
807
+ } }
808
+ }, async (ctx) => {
809
+ const { providerId } = ctx.query;
810
+ const userId = ctx.context.session.user.id;
811
+ const provider = await checkSCIMProviderAccess(ctx, userId, providerId);
812
+ return ctx.json(normalizeSCIMProvider(provider));
813
+ });
814
+ const deleteSCIMProviderConnection = () => createAuthEndpoint("/scim/delete-provider-connection", {
815
+ method: "POST",
816
+ use: [sessionMiddleware],
817
+ body: deleteSCIMProviderConnectionBodySchema,
818
+ metadata: { openapi: {
819
+ operationId: "deleteSCIMProviderConnection",
820
+ summary: "Delete SCIM provider",
821
+ description: "Deletes a SCIM provider and invalidates its token",
822
+ responses: {
823
+ "200": {
824
+ description: "SCIM provider deleted successfully",
825
+ content: { "application/json": { schema: {
826
+ type: "object",
827
+ properties: { success: { type: "boolean" } }
828
+ } } }
829
+ },
830
+ "404": { description: "Provider not found" },
831
+ "403": { description: "Access denied" }
832
+ }
833
+ } }
834
+ }, async (ctx) => {
835
+ const { providerId } = ctx.body;
836
+ const userId = ctx.context.session.user.id;
837
+ await checkSCIMProviderAccess(ctx, userId, providerId);
838
+ await ctx.context.adapter.delete({
839
+ model: "scimProvider",
840
+ where: [{
841
+ field: "providerId",
842
+ value: providerId
843
+ }]
844
+ });
845
+ return ctx.json({ success: true });
846
+ });
699
847
  const createSCIMUser = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
700
848
  method: "POST",
701
849
  body: APIUserSchema,
@@ -1276,6 +1424,7 @@ const parseSCIMAPIUserFilter = (filter) => {
1276
1424
  const scim = (options) => {
1277
1425
  const opts = {
1278
1426
  storeSCIMToken: "plain",
1427
+ providerOwnership: { enabled: false },
1279
1428
  ...options
1280
1429
  };
1281
1430
  const authMiddleware = authMiddlewareFactory(opts);
@@ -1283,6 +1432,9 @@ const scim = (options) => {
1283
1432
  id: "scim",
1284
1433
  endpoints: {
1285
1434
  generateSCIMToken: generateSCIMToken(opts),
1435
+ listSCIMProviderConnections: listSCIMProviderConnections(),
1436
+ getSCIMProviderConnection: getSCIMProviderConnection(),
1437
+ deleteSCIMProviderConnection: deleteSCIMProviderConnection(),
1286
1438
  getSCIMUser: getSCIMUser(authMiddleware),
1287
1439
  createSCIMUser: createSCIMUser(authMiddleware),
1288
1440
  patchSCIMUser: patchSCIMUser(authMiddleware),
@@ -1309,7 +1461,11 @@ const scim = (options) => {
1309
1461
  organizationId: {
1310
1462
  type: "string",
1311
1463
  required: false
1312
- }
1464
+ },
1465
+ ...opts.providerOwnership?.enabled ? { userId: {
1466
+ type: "string",
1467
+ required: false
1468
+ } } : {}
1313
1469
  } } },
1314
1470
  options
1315
1471
  };