@better-auth/scim 1.5.0-beta.10 → 1.5.0-beta.11

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,5 +1,5 @@
1
1
 
2
- > @better-auth/scim@1.5.0-beta.10 build /home/runner/work/better-auth/better-auth/packages/scim
2
+ > @better-auth/scim@1.5.0-beta.11 build /home/runner/work/better-auth/better-auth/packages/scim
3
3
  > tsdown
4
4
 
5
5
  ℹ tsdown v0.20.1 powered by rolldown v1.0.0-rc.1
@@ -7,13 +7,13 @@
7
7
  ℹ entry: src/index.ts, src/client.ts
8
8
  ℹ tsconfig: tsconfig.json
9
9
  ℹ Build start
10
- ℹ dist/index.mjs  39.35 kB │ gzip: 8.02 kB
10
+ ℹ dist/index.mjs  39.32 kB │ gzip: 8.01 kB
11
11
  ℹ dist/client.mjs  0.19 kB │ gzip: 0.17 kB
12
- ℹ dist/index.mjs.map  78.15 kB │ gzip: 15.16 kB
12
+ ℹ dist/index.mjs.map  78.16 kB │ gzip: 15.17 kB
13
13
  ℹ dist/client.mjs.map  0.46 kB │ gzip: 0.30 kB
14
- ℹ dist/index.d.mts 108.76 kB │ gzip: 4.44 kB
14
+ ℹ dist/index.d.mts 108.88 kB │ gzip: 4.45 kB
15
15
  ℹ dist/client.d.mts  0.24 kB │ gzip: 0.20 kB
16
- ℹ 6 files, total: 227.15 kB
16
+ ℹ 6 files, total: 227.23 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 8835ms
19
+ ✔ Build complete in 8780ms
package/dist/index.d.mts CHANGED
@@ -125,7 +125,7 @@ declare const scim: (options?: SCIMOptions) => {
125
125
  updatedAt: Date;
126
126
  email: string;
127
127
  emailVerified: boolean;
128
- name: string;
128
+ name?: string | null | undefined;
129
129
  image?: string | null | undefined;
130
130
  };
131
131
  };
@@ -400,8 +400,8 @@ declare const scim: (options?: SCIMOptions) => {
400
400
  userName: string;
401
401
  name: {
402
402
  formatted: string;
403
- };
404
- displayName: string;
403
+ } | undefined;
404
+ displayName: string | undefined;
405
405
  active: boolean;
406
406
  emails: {
407
407
  primary: boolean;
@@ -689,8 +689,8 @@ declare const scim: (options?: SCIMOptions) => {
689
689
  userName: string;
690
690
  name: {
691
691
  formatted: string;
692
- };
693
- displayName: string;
692
+ } | undefined;
693
+ displayName: string | undefined;
694
694
  active: boolean;
695
695
  emails: {
696
696
  primary: boolean;
@@ -1354,8 +1354,8 @@ declare const scim: (options?: SCIMOptions) => {
1354
1354
  userName: string;
1355
1355
  name: {
1356
1356
  formatted: string;
1357
- };
1358
- displayName: string;
1357
+ } | undefined;
1358
+ displayName: string | undefined;
1359
1359
  active: boolean;
1360
1360
  emails: {
1361
1361
  primary: boolean;
@@ -1655,8 +1655,8 @@ declare const scim: (options?: SCIMOptions) => {
1655
1655
  userName: string;
1656
1656
  name: {
1657
1657
  formatted: string;
1658
- };
1659
- displayName: string;
1658
+ } | undefined;
1659
+ displayName: string | undefined;
1660
1660
  active: boolean;
1661
1661
  emails: {
1662
1662
  primary: boolean;
package/dist/index.mjs CHANGED
@@ -132,15 +132,13 @@ const getAccountId = (userName, externalId) => {
132
132
  const getFormattedName = (name) => {
133
133
  if (name.givenName && name.familyName) return `${name.givenName} ${name.familyName}`;
134
134
  if (name.givenName) return name.givenName;
135
- return name.familyName ?? "";
135
+ return name.familyName;
136
136
  };
137
- const getUserFullName = (email, name) => {
138
- if (name) {
139
- const formatted = name.formatted?.trim() ?? "";
140
- if (formatted.length > 0) return formatted;
141
- return getFormattedName(name) || email;
142
- }
143
- return email;
137
+ const getUserFullName = (name) => {
138
+ if (!name) return;
139
+ const formatted = name.formatted?.trim();
140
+ if (formatted) return formatted;
141
+ return getFormattedName(name);
144
142
  };
145
143
  const getUserPrimaryEmail = (userName, emails) => {
146
144
  return emails?.find((email) => email.primary)?.value ?? emails?.[0]?.value ?? userName;
@@ -155,18 +153,18 @@ const lowerCase = (user, op, resources) => {
155
153
  return op.value.toLowerCase();
156
154
  };
157
155
  const givenName = (user, op, resources) => {
158
- const familyName = (resources.user.name ?? user.name).split(" ").slice(1).join(" ").trim();
156
+ const familyName = (resources.user.name ?? user.name)?.split(" ").slice(1).join(" ").trim();
159
157
  const givenName = op.value;
160
- return getUserFullName(user.email, {
158
+ return getUserFullName({
161
159
  givenName,
162
160
  familyName
163
161
  });
164
162
  };
165
163
  const familyName = (user, op, resources) => {
166
164
  const currentName = resources.user.name ?? user.name;
167
- const givenName = (currentName.split(" ").slice(0, -1).join(" ") || currentName).trim();
165
+ const givenName = currentName ? (currentName.split(" ").slice(0, -1).join(" ") || currentName).trim() : void 0;
168
166
  const familyName = op.value;
169
- return getUserFullName(user.email, {
167
+ return getUserFullName({
170
168
  givenName,
171
169
  familyName
172
170
  });
@@ -598,8 +596,8 @@ const createUserResource = (baseURL, user, account) => {
598
596
  location: getResourceURL(`/scim/v2/Users/${user.id}`, baseURL)
599
597
  },
600
598
  userName: user.email,
601
- name: { formatted: user.name },
602
- displayName: user.name,
599
+ name: user.name ? { formatted: user.name } : void 0,
600
+ displayName: user.name ?? void 0,
603
601
  active: true,
604
602
  emails: [{
605
603
  primary: true,
@@ -733,7 +731,7 @@ const createSCIMUser = (authMiddleware) => createAuthEndpoint("/scim/v2/Users",
733
731
  scimType: "uniqueness"
734
732
  });
735
733
  const email = getUserPrimaryEmail(body.userName, body.emails);
736
- const name = getUserFullName(email, body.name);
734
+ const name = getUserFullName(body.name);
737
735
  const existingUser = await ctx.context.adapter.findOne({
738
736
  model: "user",
739
737
  where: [{
@@ -827,7 +825,7 @@ const updateSCIMUser = (authMiddleware) => createAuthEndpoint("/scim/v2/Users/:u
827
825
  if (!user) throw new SCIMAPIError("NOT_FOUND", { detail: "User not found" });
828
826
  const [updatedUser, updatedAccount] = await ctx.context.adapter.transaction(async () => {
829
827
  const email = getUserPrimaryEmail(body.userName, body.emails);
830
- const name = getUserFullName(email, body.name);
828
+ const name = getUserFullName(body.name);
831
829
  return [await ctx.context.internalAdapter.updateUser(userId, {
832
830
  email,
833
831
  name,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["APIError"],"sources":["../src/scim-error.ts","../src/scim-tokens.ts","../src/middlewares.ts","../src/mappings.ts","../src/patch-operations.ts","../src/user-schemas.ts","../src/scim-filters.ts","../src/scim-metadata.ts","../src/utils.ts","../src/scim-resources.ts","../src/routes.ts","../src/index.ts"],"sourcesContent":["import type { Status } from \"better-auth\";\nimport { APIError } from \"better-auth\";\nimport { statusCodes } from \"better-call\";\n\n/**\n * SCIM compliant error\n * See: https://datatracker.ietf.org/doc/html/rfc7644#section-3.12\n */\nexport class SCIMAPIError extends APIError {\n\tconstructor(\n\t\tstatus: keyof typeof statusCodes | Status = \"INTERNAL_SERVER_ERROR\",\n\t\toverrides: any = {},\n\t) {\n\t\tconst body = {\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:Error\"],\n\t\t\tstatus: (typeof status === \"number\"\n\t\t\t\t? status\n\t\t\t\t: statusCodes[status]\n\t\t\t).toString(),\n\t\t\tdetail: overrides.detail,\n\t\t\t...overrides,\n\t\t};\n\t\tsuper(status, body);\n\t\tthis.message = body.detail ?? body.message;\n\t}\n}\n\nconst SCIMErrorOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tstatus: {\n\t\t\ttype: \"string\",\n\t\t},\n\t\tdetail: {\n\t\t\ttype: \"string\",\n\t\t},\n\t\tscimType: {\n\t\t\ttype: \"string\",\n\t\t},\n\t},\n} as const;\n\nexport const SCIMErrorOpenAPISchemas = {\n\t\"400\": {\n\t\tdescription:\n\t\t\t\"Bad Request. Usually due to missing parameters, or invalid parameters\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"401\": {\n\t\tdescription: \"Unauthorized. Due to missing or invalid authentication.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"403\": {\n\t\tdescription: \"Unauthorized. Due to missing or invalid authentication.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"404\": {\n\t\tdescription: \"Not Found. The requested resource was not found.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"429\": {\n\t\tdescription:\n\t\t\t\"Too Many Requests. You have exceeded the rate limit. Try again later.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"500\": {\n\t\tdescription:\n\t\t\t\"Internal Server Error. This is a problem with the server that you cannot fix.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n};\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport { defaultKeyHasher } from \"better-auth/plugins\";\nimport type { SCIMOptions } from \"./types\";\n\nexport async function storeSCIMToken(\n\tctx: GenericEndpointContext,\n\topts: SCIMOptions,\n\tscimToken: string,\n) {\n\tif (opts.storeSCIMToken === \"encrypted\") {\n\t\treturn await symmetricEncrypt({\n\t\t\tkey: ctx.context.secret,\n\t\t\tdata: scimToken,\n\t\t});\n\t}\n\tif (opts.storeSCIMToken === \"hashed\") {\n\t\treturn await defaultKeyHasher(scimToken);\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"hash\" in opts.storeSCIMToken\n\t) {\n\t\treturn await opts.storeSCIMToken.hash(scimToken);\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"encrypt\" in opts.storeSCIMToken\n\t) {\n\t\treturn await opts.storeSCIMToken.encrypt(scimToken);\n\t}\n\n\treturn scimToken;\n}\n\nexport async function verifySCIMToken(\n\tctx: GenericEndpointContext,\n\topts: SCIMOptions,\n\tstoredSCIMToken: string,\n\tscimToken: string,\n): Promise<boolean> {\n\tif (opts.storeSCIMToken === \"encrypted\") {\n\t\treturn (\n\t\t\t(await symmetricDecrypt({\n\t\t\t\tkey: ctx.context.secret,\n\t\t\t\tdata: storedSCIMToken,\n\t\t\t})) === scimToken\n\t\t);\n\t}\n\tif (opts.storeSCIMToken === \"hashed\") {\n\t\tconst hashedSCIMToken = await defaultKeyHasher(scimToken);\n\t\treturn hashedSCIMToken === storedSCIMToken;\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"hash\" in opts.storeSCIMToken\n\t) {\n\t\tconst hashedSCIMToken = await opts.storeSCIMToken.hash(scimToken);\n\t\treturn hashedSCIMToken === storedSCIMToken;\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"decrypt\" in opts.storeSCIMToken\n\t) {\n\t\tconst decryptedSCIMToken =\n\t\t\tawait opts.storeSCIMToken.decrypt(storedSCIMToken);\n\t\treturn decryptedSCIMToken === scimToken;\n\t}\n\n\treturn scimToken === storedSCIMToken;\n}\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport { createAuthMiddleware } from \"better-auth/api\";\nimport { SCIMAPIError } from \"./scim-error\";\nimport { verifySCIMToken } from \"./scim-tokens\";\nimport type { SCIMOptions, SCIMProvider } from \"./types\";\n\nexport type AuthMiddleware = ReturnType<typeof authMiddlewareFactory>;\n\n/**\n * The middleware forces the endpoint to have a valid token\n */\nexport const authMiddlewareFactory = (opts: SCIMOptions) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tconst authHeader = ctx.headers?.get(\"Authorization\");\n\t\tconst authSCIMToken = authHeader?.replace(/^Bearer\\s+/i, \"\");\n\n\t\tif (!authSCIMToken) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"SCIM token is required\",\n\t\t\t});\n\t\t}\n\n\t\tconst baseScimTokenParts = new TextDecoder()\n\t\t\t.decode(base64Url.decode(authSCIMToken))\n\t\t\t.split(\":\");\n\n\t\tconst [scimToken, providerId] = baseScimTokenParts;\n\t\tconst organizationId = baseScimTokenParts.slice(2).join(\":\");\n\n\t\tif (!scimToken || !providerId) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\tlet scimProvider: Omit<SCIMProvider, \"id\"> | null =\n\t\t\topts.defaultSCIM?.find((p) => {\n\t\t\t\tif (p.providerId === providerId && !organizationId) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn !!(\n\t\t\t\t\tp.providerId === providerId &&\n\t\t\t\t\torganizationId &&\n\t\t\t\t\tp.organizationId === organizationId\n\t\t\t\t);\n\t\t\t}) ?? null;\n\n\t\tif (scimProvider) {\n\t\t\tif (scimProvider.scimToken === scimToken) {\n\t\t\t\treturn { authSCIMToken: scimProvider.scimToken, scimProvider };\n\t\t\t} else {\n\t\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tscimProvider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\t\tmodel: \"scimProvider\",\n\t\t\twhere: [\n\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t...(organizationId\n\t\t\t\t\t? [{ field: \"organizationId\", value: organizationId }]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t});\n\n\t\tif (!scimProvider) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\tconst isValidToken = await verifySCIMToken(\n\t\t\tctx,\n\t\t\topts,\n\t\t\tscimProvider.scimToken,\n\t\t\tscimToken,\n\t\t);\n\n\t\tif (!isValidToken) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\treturn { authSCIMToken: scimToken, scimProvider };\n\t});\n","import type { SCIMEmail, SCIMName } from \"./types\";\n\nexport const getAccountId = (userName: string, externalId?: string) => {\n\treturn externalId ?? userName;\n};\n\nconst getFormattedName = (name: SCIMName) => {\n\tif (name.givenName && name.familyName) {\n\t\treturn `${name.givenName} ${name.familyName}`;\n\t}\n\n\tif (name.givenName) {\n\t\treturn name.givenName;\n\t}\n\n\treturn name.familyName ?? \"\";\n};\n\nexport const getUserFullName = (email: string, name?: SCIMName) => {\n\tif (name) {\n\t\tconst formatted = name.formatted?.trim() ?? \"\";\n\t\tif (formatted.length > 0) {\n\t\t\treturn formatted;\n\t\t}\n\n\t\treturn getFormattedName(name) || email;\n\t}\n\n\treturn email;\n};\n\nexport const getUserPrimaryEmail = (userName: string, emails?: SCIMEmail[]) => {\n\treturn (\n\t\temails?.find((email) => email.primary)?.value ??\n\t\temails?.[0]?.value ??\n\t\tuserName\n\t);\n};\n","import type { User } from \"better-auth\";\nimport { getUserFullName } from \"./mappings\";\n\ntype Operation = {\n\top: \"add\" | \"remove\" | \"replace\";\n\tvalue: any;\n\tpath?: string;\n};\n\ntype Mapping = {\n\ttarget: string;\n\tresource: \"user\" | \"account\";\n\tmap: (user: User, op: Operation, resources: Resources) => any;\n};\n\ntype Resources = {\n\tuser: Record<string, any>;\n\taccount: Record<string, any>;\n};\n\nconst identity = (user: User, op: Operation, resources: Resources) => {\n\treturn op.value;\n};\n\nconst lowerCase = (user: User, op: Operation, resources: Resources) => {\n\treturn op.value.toLowerCase();\n};\n\nconst givenName = (user: User, op: Operation, resources: Resources) => {\n\tconst currentName = (resources.user.name as string) ?? user.name;\n\tconst familyName = currentName.split(\" \").slice(1).join(\" \").trim();\n\tconst givenName = op.value;\n\n\treturn getUserFullName(user.email, {\n\t\tgivenName,\n\t\tfamilyName,\n\t});\n};\n\nconst familyName = (user: User, op: Operation, resources: Resources) => {\n\tconst currentName = (resources.user.name as string) ?? user.name;\n\tconst givenName = (\n\t\tcurrentName.split(\" \").slice(0, -1).join(\" \") || currentName\n\t).trim();\n\tconst familyName = op.value;\n\treturn getUserFullName(user.email, {\n\t\tgivenName,\n\t\tfamilyName,\n\t});\n};\n\nconst userPatchMappings: Record<string, Mapping> = {\n\t\"/name/formatted\": { resource: \"user\", target: \"name\", map: identity },\n\t\"/name/givenName\": { resource: \"user\", target: \"name\", map: givenName },\n\t\"/name/familyName\": {\n\t\tresource: \"user\",\n\t\ttarget: \"name\",\n\t\tmap: familyName,\n\t},\n\t\"/externalId\": {\n\t\tresource: \"account\",\n\t\ttarget: \"accountId\",\n\t\tmap: identity,\n\t},\n\t\"/userName\": { resource: \"user\", target: \"email\", map: lowerCase },\n};\n\nconst normalizePath = (path: string): string => {\n\tconst withoutLeadingSlash = path.startsWith(\"/\") ? path.slice(1) : path;\n\treturn `/${withoutLeadingSlash.replaceAll(\".\", \"/\")}`;\n};\n\nconst isNestedObject = (value: unknown): value is Record<string, unknown> => {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst applyMapping = (\n\tuser: User,\n\tresources: Resources,\n\tpath: string,\n\tvalue: unknown,\n\top: \"add\" | \"replace\",\n) => {\n\tconst normalizedPath = normalizePath(path);\n\tconst mapping = userPatchMappings[normalizedPath];\n\n\tif (!mapping) {\n\t\treturn;\n\t}\n\n\tconst newValue = mapping.map(\n\t\tuser,\n\t\t{\n\t\t\top,\n\t\t\tvalue,\n\t\t\tpath: normalizedPath,\n\t\t},\n\t\tresources,\n\t);\n\n\tif (op === \"add\" && mapping.resource === \"user\") {\n\t\tconst currentValue = (user as Record<string, unknown>)[mapping.target];\n\t\tif (currentValue === newValue) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tresources[mapping.resource][mapping.target] = newValue;\n};\n\nconst applyPatchValue = (\n\tuser: User,\n\tresources: Resources,\n\tvalue: unknown,\n\top: \"add\" | \"replace\",\n\tpath?: string | undefined,\n) => {\n\tif (isNestedObject(value)) {\n\t\tfor (const [key, nestedValue] of Object.entries(value)) {\n\t\t\tconst nestedPath = path ? `${path}.${key}` : key;\n\t\t\tapplyPatchValue(user, resources, nestedValue, op, nestedPath);\n\t\t}\n\t} else if (path) {\n\t\tapplyMapping(user, resources, path, value, op);\n\t}\n};\n\nexport const buildUserPatch = (user: User, operations: Operation[]) => {\n\tconst userPatch: Record<string, any> = {};\n\tconst accountPatch: Record<string, any> = {};\n\tconst resources: Resources = { user: userPatch, account: accountPatch };\n\n\tfor (const operation of operations) {\n\t\tif (operation.op !== \"add\" && operation.op !== \"replace\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tapplyPatchValue(\n\t\t\tuser,\n\t\t\tresources,\n\t\t\toperation.value,\n\t\t\toperation.op,\n\t\t\toperation.path,\n\t\t);\n\t}\n\n\treturn resources;\n};\n","import * as z from \"zod\";\n\nexport const APIUserSchema = z.object({\n\tuserName: z.string().lowercase(),\n\texternalId: z.string().optional(),\n\tname: z\n\t\t.object({\n\t\t\tformatted: z.string().optional(),\n\t\t\tgivenName: z.string().optional(),\n\t\t\tfamilyName: z.string().optional(),\n\t\t})\n\t\t.optional(),\n\temails: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tvalue: z.email(),\n\t\t\t\tprimary: z.boolean().optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\nexport const OpenAPIUserResourceSchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tid: { type: \"string\" },\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tcreated: { type: \"string\", format: \"date-time\" },\n\t\t\t\tlastModified: { type: \"string\", format: \"date-time\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tuserName: { type: \"string\" },\n\t\tname: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tformatted: { type: \"string\" },\n\t\t\t\tgivenName: { type: \"string\" },\n\t\t\t\tfamilyName: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tdisplayName: { type: \"string\" },\n\t\tactive: { type: \"boolean\" },\n\t\temails: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\tvalue: { type: \"string\" },\n\t\t\t\t\tprimary: { type: \"boolean\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t},\n} as const;\n\nexport const SCIMUserResourceSchema = {\n\tid: \"urn:ietf:params:scim:schemas:core:2.0:User\",\n\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:Schema\"],\n\tname: \"User\",\n\tdescription: \"User Account\",\n\tattributes: [\n\t\t{\n\t\t\tname: \"id\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription: \"Unique opaque identifier for the User\",\n\t\t\trequired: false,\n\t\t\tcaseExact: true,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"server\",\n\t\t},\n\t\t{\n\t\t\tname: \"userName\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"Unique identifier for the User, typically used by the user to directly authenticate to the service provider\",\n\t\t\trequired: true,\n\t\t\tcaseExact: false,\n\t\t\tmutability: \"readWrite\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"server\",\n\t\t},\n\t\t{\n\t\t\tname: \"displayName\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"The name of the User, suitable for display to end-users. The name SHOULD be the full name of the User being described, if known.\",\n\t\t\trequired: false,\n\t\t\tcaseExact: true,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"none\",\n\t\t},\n\t\t{\n\t\t\tname: \"active\",\n\t\t\ttype: \"boolean\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"A Boolean value indicating the User's administrative status.\",\n\t\t\trequired: false,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t},\n\t\t{\n\t\t\tname: \"name\",\n\t\t\ttype: \"complex\",\n\t\t\tmultiValued: false,\n\t\t\tdescription: \"The components of the user's real name.\",\n\t\t\trequired: false,\n\t\t\tsubAttributes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"formatted\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The full name, including all middlenames, titles, and suffixes as appropriate, formatted for display(e.g., 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"familyName\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The family name of the User, or last name in most Western languages (e.g., 'Jensen' given the fullname 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"givenName\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The given name of the User, or first name in most Western languages (e.g., 'Barbara' given the full name 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tname: \"emails\",\n\t\t\ttype: \"complex\",\n\t\t\tmultiValued: true,\n\t\t\tdescription:\n\t\t\t\t\"Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.\",\n\t\t\trequired: false,\n\t\t\tsubAttributes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"server\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"primary\",\n\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address. The primary attribute value 'true' MUST appear no more than once.\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tmutability: \"readWrite\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"none\",\n\t\t},\n\t],\n\tmeta: {\n\t\tresourceType: \"Schema\",\n\t\tlocation: \"/scim/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User\",\n\t},\n};\n\nexport const SCIMUserResourceType = {\n\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:ResourceType\"],\n\tid: \"User\",\n\tname: \"User\",\n\tendpoint: \"/Users\",\n\tdescription: \"User Account\",\n\tschema: \"urn:ietf:params:scim:schemas:core:2.0:User\",\n\tmeta: {\n\t\tresourceType: \"ResourceType\",\n\t\tlocation: \"/scim/v2/ResourceTypes/User\",\n\t},\n};\n","import { SCIMUserResourceSchema } from \"./user-schemas\";\n\nexport type DBFilter = {\n\tfield: string;\n\tvalue: string | string[];\n\toperator?: any;\n};\n\nconst SCIMOperators: Record<string, string | undefined> = {\n\teq: \"eq\",\n};\n\nconst SCIMUserAttributes: Record<string, string | undefined> = {\n\tuserName: \"email\",\n};\n\nexport class SCIMParseError extends Error {}\n\nconst SCIMFilterRegex =\n\t/^\\s*(?<attribute>[^\\s]+)\\s+(?<op>eq|ne|co|sw|ew|pr)\\s*(?:(?<value>\"[^\"]*\"|[^\\s]+))?\\s*$/i;\n\nconst parseSCIMFilter = (filter: string) => {\n\tconst match = filter.match(SCIMFilterRegex);\n\tif (!match) {\n\t\tthrow new SCIMParseError(\"Invalid filter expression\");\n\t}\n\n\tconst attribute = match.groups?.attribute;\n\tconst op = match.groups?.op?.toLowerCase();\n\tconst value = match.groups?.value;\n\n\tif (!attribute || !op || !value) {\n\t\tthrow new SCIMParseError(\"Invalid filter expression\");\n\t}\n\n\tconst operator = SCIMOperators[op];\n\tif (!operator) {\n\t\tthrow new SCIMParseError(`The operator \"${op}\" is not supported`);\n\t}\n\n\treturn { attribute, operator, value };\n};\n\nexport const parseSCIMUserFilter = (filter: string) => {\n\tconst { attribute, operator, value } = parseSCIMFilter(filter);\n\n\tconst filters: DBFilter[] = [];\n\tconst targetAttribute = SCIMUserAttributes[attribute];\n\tconst resourceAttribute = SCIMUserResourceSchema.attributes.find(\n\t\t(attr) => attr.name === attribute,\n\t);\n\n\tif (!targetAttribute || !resourceAttribute) {\n\t\tthrow new SCIMParseError(`The attribute \"${attribute}\" is not supported`);\n\t}\n\n\tlet finalValue = value.replaceAll('\"', \"\");\n\tif (!resourceAttribute.caseExact) {\n\t\tfinalValue = finalValue.toLowerCase();\n\t}\n\n\tfilters.push({\n\t\tfield: targetAttribute,\n\t\tvalue: finalValue,\n\t\toperator,\n\t});\n\n\treturn filters;\n};\n","const MetadataFieldSupportOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tsupported: {\n\t\t\ttype: \"boolean\",\n\t\t},\n\t},\n};\n\nexport const ServiceProviderOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tpatch: MetadataFieldSupportOpenAPISchema,\n\t\tbulk: MetadataFieldSupportOpenAPISchema,\n\t\tfilter: MetadataFieldSupportOpenAPISchema,\n\t\tchangePassword: MetadataFieldSupportOpenAPISchema,\n\t\tsort: MetadataFieldSupportOpenAPISchema,\n\t\tetag: MetadataFieldSupportOpenAPISchema,\n\t\tauthenticationSchemes: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tdescription: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tspecUri: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\ttype: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tprimary: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"string\",\n\t\t\t},\n\t\t},\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nexport const ResourceTypeOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tid: { type: \"string\" },\n\t\tname: { type: \"string\" },\n\t\tendpoint: { type: \"string\" },\n\t\tdescription: { type: \"string\" },\n\t\tschema: { type: \"string\" },\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nconst SCIMSchemaAttributesOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tname: { type: \"string\" },\n\t\ttype: { type: \"string\" },\n\t\tmultiValued: { type: \"boolean\" },\n\t\tdescription: { type: \"string\" },\n\t\trequired: { type: \"boolean\" },\n\t\tcaseExact: { type: \"boolean\" },\n\t\tmutability: { type: \"string\" },\n\t\treturned: { type: \"string\" },\n\t\tuniqueness: { type: \"string\" },\n\t},\n} as const;\n\nexport const SCIMSchemaOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tid: { type: \"string\" },\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tname: { type: \"string\" },\n\t\tdescription: { type: \"string\" },\n\t\tattributes: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\t...SCIMSchemaAttributesOpenAPISchema,\n\t\t\t\tproperties: {\n\t\t\t\t\t...SCIMSchemaAttributesOpenAPISchema.properties,\n\t\t\t\t\tsubAttributes: {\n\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\titems: SCIMSchemaAttributesOpenAPISchema,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"resourceType\", \"location\"],\n\t\t},\n\t},\n} as const;\n","export const getResourceURL = (path: string, baseURL: string) => {\n\tconst normalizedBaseURL = baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`;\n\tconst normalizedPath = path.replace(/^\\/+/, \"\");\n\treturn new URL(normalizedPath, normalizedBaseURL).toString();\n};\n","import type { Account, User } from \"better-auth\";\nimport { SCIMUserResourceSchema } from \"./user-schemas\";\nimport { getResourceURL } from \"./utils\";\n\nexport const createUserResource = (\n\tbaseURL: string,\n\tuser: User,\n\taccount?: Account | null,\n) => {\n\treturn {\n\t\t// Common attributes\n\t\t// See https://datatracker.ietf.org/doc/html/rfc7643#section-3.1\n\n\t\tid: user.id,\n\t\texternalId: account?.accountId,\n\t\tmeta: {\n\t\t\tresourceType: \"User\",\n\t\t\tcreated: user.createdAt,\n\t\t\tlastModified: user.updatedAt,\n\t\t\tlocation: getResourceURL(`/scim/v2/Users/${user.id}`, baseURL),\n\t\t},\n\n\t\t// SCIM user resource\n\t\t// See https://datatracker.ietf.org/doc/html/rfc7643#section-4.1\n\n\t\tuserName: user.email,\n\t\tname: {\n\t\t\tformatted: user.name,\n\t\t},\n\t\tdisplayName: user.name,\n\t\tactive: true,\n\t\temails: [{ primary: true, value: user.email }],\n\t\tschemas: [SCIMUserResourceSchema.id],\n\t};\n};\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport type { Account, DBAdapter, User } from \"better-auth\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport {\n\tAPIError,\n\tcreateAuthEndpoint,\n\tsessionMiddleware,\n} from \"better-auth/api\";\nimport { generateRandomString } from \"better-auth/crypto\";\nimport type { Member } from \"better-auth/plugins\";\nimport * as z from \"zod\";\nimport { getAccountId, getUserFullName, getUserPrimaryEmail } from \"./mappings\";\nimport type { AuthMiddleware } from \"./middlewares\";\nimport { buildUserPatch } from \"./patch-operations\";\nimport { SCIMAPIError, SCIMErrorOpenAPISchemas } from \"./scim-error\";\nimport type { DBFilter } from \"./scim-filters\";\nimport { parseSCIMUserFilter, SCIMParseError } from \"./scim-filters\";\nimport {\n\tResourceTypeOpenAPISchema,\n\tSCIMSchemaOpenAPISchema,\n\tServiceProviderOpenAPISchema,\n} from \"./scim-metadata\";\nimport { createUserResource } from \"./scim-resources\";\nimport { storeSCIMToken } from \"./scim-tokens\";\nimport type { SCIMOptions, SCIMProvider } from \"./types\";\nimport {\n\tAPIUserSchema,\n\tOpenAPIUserResourceSchema,\n\tSCIMUserResourceSchema,\n\tSCIMUserResourceType,\n} from \"./user-schemas\";\nimport { getResourceURL } from \"./utils\";\n\nconst supportedSCIMSchemas = [SCIMUserResourceSchema];\nconst supportedSCIMResourceTypes = [SCIMUserResourceType];\nconst supportedMediaTypes = [\"application/json\", \"application/scim+json\"];\n\nconst generateSCIMTokenBodySchema = z.object({\n\tproviderId: z.string().meta({ description: \"Unique provider identifier\" }),\n\torganizationId: z\n\t\t.string()\n\t\t.optional()\n\t\t.meta({ description: \"Optional organization id\" }),\n});\n\nexport const generateSCIMToken = (opts: SCIMOptions) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/generate-token\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: generateSCIMTokenBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Generates a new SCIM token for the given provider\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Generates a new SCIM token to be used for SCIM operations\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\tdescription: \"SCIM token response\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tscimToken: {\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"SCIM token\",\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { providerId, organizationId } = ctx.body;\n\t\t\tconst user = ctx.context.session.user;\n\n\t\t\tif (providerId.includes(\":\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Provider id contains forbidden characters\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (organizationId && !ctx.context.hasPlugin(\"organization\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"Restricting a token to an organization requires the organization plugin\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet member: Member | null = null;\n\t\t\tif (organizationId) {\n\t\t\t\tmember = await ctx.context.adapter.findOne<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\t\tvalue: organizationId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (!member) {\n\t\t\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\t\t\tmessage: \"You are not a member of the organization\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst scimProvider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t\t...(organizationId\n\t\t\t\t\t\t? [{ field: \"organizationId\", value: organizationId }]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (scimProvider) {\n\t\t\t\tawait ctx.context.adapter.delete<SCIMProvider>({\n\t\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\t\twhere: [{ field: \"id\", value: scimProvider.id }],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst baseToken = generateRandomString(24);\n\t\t\tconst scimToken = base64Url.encode(\n\t\t\t\t`${baseToken}:${providerId}${organizationId ? `:${organizationId}` : \"\"}`,\n\t\t\t);\n\n\t\t\tif (opts.beforeSCIMTokenGenerated) {\n\t\t\t\tawait opts.beforeSCIMTokenGenerated({\n\t\t\t\t\tuser,\n\t\t\t\t\tmember,\n\t\t\t\t\tscimToken,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst newSCIMProvider = await ctx.context.adapter.create<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\tdata: {\n\t\t\t\t\tproviderId: providerId,\n\t\t\t\t\torganizationId: organizationId,\n\t\t\t\t\tscimToken: await storeSCIMToken(ctx, opts, baseToken),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (opts.afterSCIMTokenGenerated) {\n\t\t\t\tawait opts.afterSCIMTokenGenerated({\n\t\t\t\t\tuser,\n\t\t\t\t\tmember,\n\t\t\t\t\tscimToken,\n\t\t\t\t\tscimProvider: newSCIMProvider,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tctx.setStatus(201);\n\n\t\t\treturn ctx.json({\n\t\t\t\tscimToken,\n\t\t\t});\n\t\t},\n\t);\n\nexport const createSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: APIUserSchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Create SCIM user.\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Provision a new user into the linked organization via SCIM. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.3\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst accountId = getAccountId(body.userName, body.externalId);\n\n\t\t\tconst existingAccount = await ctx.context.adapter.findOne<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"accountId\", value: accountId },\n\t\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (existingAccount) {\n\t\t\t\tthrow new SCIMAPIError(\"CONFLICT\", {\n\t\t\t\t\tdetail: \"User already exists\",\n\t\t\t\t\tscimType: \"uniqueness\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst email = getUserPrimaryEmail(body.userName, body.emails);\n\t\t\tconst name = getUserFullName(email, body.name);\n\n\t\t\tconst existingUser = await ctx.context.adapter.findOne<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [{ field: \"email\", value: email }],\n\t\t\t});\n\n\t\t\tconst createAccount = (userId: string) =>\n\t\t\t\tctx.context.internalAdapter.createAccount({\n\t\t\t\t\tuserId: userId,\n\t\t\t\t\tproviderId: providerId,\n\t\t\t\t\taccountId: accountId,\n\t\t\t\t\taccessToken: \"\",\n\t\t\t\t\trefreshToken: \"\",\n\t\t\t\t});\n\n\t\t\tconst createUser = () =>\n\t\t\t\tctx.context.internalAdapter.createUser({\n\t\t\t\t\temail,\n\t\t\t\t\tname,\n\t\t\t\t});\n\n\t\t\tconst createOrgMembership = async (userId: string) => {\n\t\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\t\tif (organizationId) {\n\t\t\t\t\tconst isOrgMember = await ctx.context.adapter.findOne({\n\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t\t\t\t{ field: \"userId\", value: userId },\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!isOrgMember) {\n\t\t\t\t\t\treturn await ctx.context.adapter.create<Member>({\n\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tuserId: userId,\n\t\t\t\t\t\t\t\trole: \"member\",\n\t\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t\t\torganizationId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tlet user: User;\n\t\t\tlet account: Account;\n\n\t\t\tif (existingUser) {\n\t\t\t\tuser = existingUser;\n\t\t\t\taccount = await ctx.context.adapter.transaction<Account>(async () => {\n\t\t\t\t\tconst account = await createAccount(user.id);\n\t\t\t\t\tawait createOrgMembership(user.id);\n\t\t\t\t\treturn account;\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t[user, account] = await ctx.context.adapter.transaction<\n\t\t\t\t\t[User, Account]\n\t\t\t\t>(async () => {\n\t\t\t\t\tconst user = await createUser();\n\t\t\t\t\tconst account = await createAccount(user.id);\n\t\t\t\t\tawait createOrgMembership(user.id);\n\t\t\t\t\treturn [user, account];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst userResource = createUserResource(\n\t\t\t\tctx.context.baseURL,\n\t\t\t\tuser,\n\t\t\t\taccount,\n\t\t\t);\n\n\t\t\tctx.setStatus(201);\n\t\t\tctx.setHeader(\"location\", userResource.meta.location);\n\t\t\treturn ctx.json(userResource);\n\t\t},\n\t);\n\nexport const updateSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"PUT\",\n\t\t\tbody: APIUserSchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Update SCIM user.\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Updates an existing user into the linked organization via SCIM. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.3\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body;\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst { organizationId, providerId } = ctx.context.scimProvider;\n\t\t\tconst accountId = getAccountId(body.userName, body.externalId);\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst [updatedUser, updatedAccount] =\n\t\t\t\tawait ctx.context.adapter.transaction<[User | null, Account | null]>(\n\t\t\t\t\tasync () => {\n\t\t\t\t\t\tconst email = getUserPrimaryEmail(body.userName, body.emails);\n\t\t\t\t\t\tconst name = getUserFullName(email, body.name);\n\n\t\t\t\t\t\tconst updatedUser = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\t\tuserId,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst updatedAccount =\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\t\t\t\t\t\taccountId,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn [updatedUser, updatedAccount];\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\tconst userResource = createUserResource(\n\t\t\t\tctx.context.baseURL,\n\t\t\t\tupdatedUser!,\n\t\t\t\tupdatedAccount,\n\t\t\t);\n\n\t\t\treturn ctx.json(userResource);\n\t\t},\n\t);\n\nconst listSCIMUsersQuerySchema = z\n\t.object({\n\t\tfilter: z.string().optional(),\n\t})\n\t.optional();\n\nexport const listSCIMUsers = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listSCIMUsersQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"List SCIM users\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns all users provisioned via SCIM for the linked organization. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user list\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttotalResults: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\titemsPerPage: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\tstartIndex: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\tResources: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\titems: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst apiFilters: DBFilter[] = parseSCIMAPIUserFilter(ctx.query?.filter);\n\n\t\t\tctx.context.logger.info(\"Querying result with filters: \", apiFilters);\n\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst accounts = await ctx.context.adapter.findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [{ field: \"providerId\", value: providerId }],\n\t\t\t});\n\n\t\t\tconst accountUserIds = accounts.map((account) => account.userId);\n\t\t\tlet userFilters: DBFilter[] = [\n\t\t\t\t{ field: \"id\", value: accountUserIds, operator: \"in\" },\n\t\t\t];\n\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\t\t\tif (organizationId) {\n\t\t\t\tconst members = await ctx.context.adapter.findMany<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t\t\t{ field: \"userId\", value: accountUserIds, operator: \"in\" },\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tconst memberUserIds = members.map((member) => member.userId);\n\t\t\t\tuserFilters = [{ field: \"id\", value: memberUserIds, operator: \"in\" }];\n\t\t\t}\n\n\t\t\tconst users = await ctx.context.adapter.findMany<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [...userFilters, ...apiFilters],\n\t\t\t});\n\n\t\t\treturn ctx.json({\n\t\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\t\ttotalResults: users.length,\n\t\t\t\tstartIndex: 1,\n\t\t\t\titemsPerPage: users.length,\n\t\t\t\tResources: users.map((user) => {\n\t\t\t\t\tconst account = accounts.find((a) => a.userId === user.id);\n\t\t\t\t\treturn createUserResource(ctx.context.baseURL, user, account);\n\t\t\t\t}),\n\t\t\t});\n\t\t},\n\t);\n\nexport const getSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Get SCIM user details\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns the provisioned SCIM user details. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.1\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn ctx.json(createUserResource(ctx.context.baseURL, user, account));\n\t\t},\n\t);\n\nconst patchSCIMUserBodySchema = z.object({\n\tschemas: z\n\t\t.array(z.string())\n\t\t.refine(\n\t\t\t(s) => s.includes(\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"),\n\t\t\t{\n\t\t\t\tmessage: \"Invalid schemas for PatchOp\",\n\t\t\t},\n\t\t),\n\tOperations: z.array(\n\t\tz.object({\n\t\t\top: z\n\t\t\t\t.string()\n\t\t\t\t.toLowerCase()\n\t\t\t\t.default(\"replace\")\n\t\t\t\t.pipe(z.enum([\"replace\", \"add\", \"remove\"])),\n\t\t\tpath: z.string().optional(),\n\t\t\tvalue: z.any(),\n\t\t}),\n\t),\n});\n\nexport const patchSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"PATCH\",\n\t\t\tbody: patchSCIMUserBodySchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Patch SCIM user\",\n\t\t\t\t\tdescription: \"Updates fields on a SCIM user record\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"204\": {\n\t\t\t\t\t\t\tdescription: \"Patch update applied correctly\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst { user: userPatch, account: accountPatch } = buildUserPatch(\n\t\t\t\tuser,\n\t\t\t\tctx.body.Operations,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tObject.keys(userPatch).length === 0 &&\n\t\t\t\tObject.keys(accountPatch).length === 0\n\t\t\t) {\n\t\t\t\tthrow new SCIMAPIError(\"BAD_REQUEST\", {\n\t\t\t\t\tdetail: \"No valid fields to update\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait Promise.all([\n\t\t\t\tObject.keys(userPatch).length > 0\n\t\t\t\t\t? ctx.context.internalAdapter.updateUser(userId, {\n\t\t\t\t\t\t\t...userPatch,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(),\n\t\t\t\tObject.keys(accountPatch).length > 0\n\t\t\t\t\t? ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\t\t\t\t\t...accountPatch,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(),\n\t\t\t]);\n\n\t\t\tctx.setStatus(204);\n\t\t\treturn;\n\t\t},\n\t);\n\nexport const deleteSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"DELETE\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: [...supportedMediaTypes, \"\"],\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Delete SCIM user\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Deletes (or deactivates) a user within the linked organization.\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"204\": {\n\t\t\t\t\t\t\tdescription: \"Delete applied successfully\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\tconst { user } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait ctx.context.internalAdapter.deleteUser(userId);\n\n\t\t\tctx.setStatus(204);\n\t\t\treturn;\n\t\t},\n\t);\n\nexport const getSCIMServiceProviderConfig = createAuthEndpoint(\n\t\"/scim/v2/ServiceProviderConfig\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Configuration\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: ServiceProviderOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\tpatch: { supported: true },\n\t\t\tbulk: { supported: false },\n\t\t\tfilter: { supported: true },\n\t\t\tchangePassword: { supported: false },\n\t\t\tsort: { supported: false },\n\t\t\tetag: { supported: false },\n\t\t\tauthenticationSchemes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"OAuth Bearer Token\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Authentication scheme using the Authorization header with a bearer token tied to an organization.\",\n\t\t\t\t\tspecUri: \"http://www.rfc-editor.org/info/rfc6750\",\n\t\t\t\t\ttype: \"oauthbearertoken\",\n\t\t\t\t\tprimary: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\"],\n\t\t\tmeta: {\n\t\t\t\tresourceType: \"ServiceProviderConfig\",\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const getSCIMSchemas = createAuthEndpoint(\n\t\"/scim/v2/Schemas\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Configuration Schemas\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to acquire information about supported schemas. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\titems: SCIMSchemaOpenAPISchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\ttotalResults: supportedSCIMSchemas.length,\n\t\t\titemsPerPage: supportedSCIMSchemas.length,\n\t\t\tstartIndex: 1,\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\tResources: supportedSCIMSchemas.map((s) => {\n\t\t\t\treturn {\n\t\t\t\t\t...s,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\t...s.meta,\n\t\t\t\t\t\tlocation: getResourceURL(s.meta.location, ctx.context.baseURL),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t},\n);\n\nexport const getSCIMSchema = createAuthEndpoint(\n\t\"/scim/v2/Schemas/:schemaId\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM a Service Provider Configuration Schema\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to acquire information about a given schema. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: SCIMSchemaOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst schema = supportedSCIMSchemas.find(\n\t\t\t(s) => s.id === ctx.params.schemaId,\n\t\t);\n\n\t\tif (!schema) {\n\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\tdetail: \"Schema not found\",\n\t\t\t});\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\t...schema,\n\t\t\tmeta: {\n\t\t\t\t...schema.meta,\n\t\t\t\tlocation: getResourceURL(schema.meta.location, ctx.context.baseURL),\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const getSCIMResourceTypes = createAuthEndpoint(\n\t\"/scim/v2/ResourceTypes\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Supported Resource Types\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to get a list of server supported types. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttotalResults: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\titemsPerPage: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\tstartIndex: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\tResources: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\titems: ResourceTypeOpenAPISchema,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\ttotalResults: supportedSCIMResourceTypes.length,\n\t\t\titemsPerPage: supportedSCIMResourceTypes.length,\n\t\t\tstartIndex: 1,\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\tResources: supportedSCIMResourceTypes.map((s) => {\n\t\t\t\treturn {\n\t\t\t\t\t...s,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\t...s.meta,\n\t\t\t\t\t\tlocation: getResourceURL(s.meta.location, ctx.context.baseURL),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t},\n);\n\nexport const getSCIMResourceType = createAuthEndpoint(\n\t\"/scim/v2/ResourceTypes/:resourceTypeId\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Supported Resource Type\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to get a server supported type. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: ResourceTypeOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst resourceType = supportedSCIMResourceTypes.find(\n\t\t\t(s) => s.id === ctx.params.resourceTypeId,\n\t\t);\n\n\t\tif (!resourceType) {\n\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\tdetail: \"Resource type not found\",\n\t\t\t});\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\t...resourceType,\n\t\t\tmeta: {\n\t\t\t\t...resourceType.meta,\n\t\t\t\tlocation: getResourceURL(\n\t\t\t\t\tresourceType.meta.location,\n\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t},\n);\n\nconst findUserById = async (\n\tadapter: DBAdapter,\n\t{\n\t\tuserId,\n\t\tproviderId,\n\t\torganizationId,\n\t}: { userId: string; providerId: string; organizationId?: string },\n) => {\n\tconst account = await adapter.findOne<Account>({\n\t\tmodel: \"account\",\n\t\twhere: [\n\t\t\t{ field: \"userId\", value: userId },\n\t\t\t{ field: \"providerId\", value: providerId },\n\t\t],\n\t});\n\n\t// Disallows access to the resource\n\t// Account is not associated to the provider\n\n\tif (!account) {\n\t\treturn { user: null, account: null };\n\t}\n\n\tlet member: Member | null = null;\n\tif (organizationId) {\n\t\tmember = await adapter.findOne<Member>({\n\t\t\tmodel: \"member\",\n\t\t\twhere: [\n\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t{ field: \"userId\", value: userId },\n\t\t\t],\n\t\t});\n\t}\n\n\t// Disallows access to the resource\n\t// Token is restricted to an org and the member is not part of it\n\n\tif (organizationId && !member) {\n\t\treturn { user: null, account: null };\n\t}\n\n\tconst user = await adapter.findOne<User>({\n\t\tmodel: \"user\",\n\t\twhere: [{ field: \"id\", value: userId }],\n\t});\n\n\tif (!user) {\n\t\treturn { user: null, account: null };\n\t}\n\n\treturn { user, account };\n};\n\nconst parseSCIMAPIUserFilter = (filter?: string) => {\n\tlet filters: DBFilter[] = [];\n\n\ttry {\n\t\tfilters = filter ? parseSCIMUserFilter(filter) : [];\n\t} catch (error) {\n\t\tthrow new SCIMAPIError(\"BAD_REQUEST\", {\n\t\t\tdetail:\n\t\t\t\terror instanceof SCIMParseError ? error.message : \"Invalid SCIM filter\",\n\t\t\tscimType: \"invalidFilter\",\n\t\t});\n\t}\n\n\treturn filters;\n};\n","import type { BetterAuthPlugin } from \"better-auth\";\nimport { authMiddlewareFactory } from \"./middlewares\";\nimport {\n\tcreateSCIMUser,\n\tdeleteSCIMUser,\n\tgenerateSCIMToken,\n\tgetSCIMResourceType,\n\tgetSCIMResourceTypes,\n\tgetSCIMSchema,\n\tgetSCIMSchemas,\n\tgetSCIMServiceProviderConfig,\n\tgetSCIMUser,\n\tlistSCIMUsers,\n\tpatchSCIMUser,\n\tupdateSCIMUser,\n} from \"./routes\";\nimport type { SCIMOptions } from \"./types\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\tscim: {\n\t\t\tcreator: typeof scim;\n\t\t};\n\t}\n}\n\nexport const scim = (options?: SCIMOptions) => {\n\tconst opts = {\n\t\tstoreSCIMToken: \"plain\",\n\t\t...options,\n\t} satisfies SCIMOptions;\n\n\tconst authMiddleware = authMiddlewareFactory(opts);\n\n\treturn {\n\t\tid: \"scim\",\n\t\tendpoints: {\n\t\t\tgenerateSCIMToken: generateSCIMToken(opts),\n\t\t\tgetSCIMUser: getSCIMUser(authMiddleware),\n\t\t\tcreateSCIMUser: createSCIMUser(authMiddleware),\n\t\t\tpatchSCIMUser: patchSCIMUser(authMiddleware),\n\t\t\tdeleteSCIMUser: deleteSCIMUser(authMiddleware),\n\t\t\tupdateSCIMUser: updateSCIMUser(authMiddleware),\n\t\t\tlistSCIMUsers: listSCIMUsers(authMiddleware),\n\t\t\tgetSCIMServiceProviderConfig,\n\t\t\tgetSCIMSchemas,\n\t\t\tgetSCIMSchema,\n\t\t\tgetSCIMResourceTypes,\n\t\t\tgetSCIMResourceType,\n\t\t},\n\t\tschema: {\n\t\t\tscimProvider: {\n\t\t\t\tfields: {\n\t\t\t\t\tproviderId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\tscimToken: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\torganizationId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport * from \"./types\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["APIError"],"sources":["../src/scim-error.ts","../src/scim-tokens.ts","../src/middlewares.ts","../src/mappings.ts","../src/patch-operations.ts","../src/user-schemas.ts","../src/scim-filters.ts","../src/scim-metadata.ts","../src/utils.ts","../src/scim-resources.ts","../src/routes.ts","../src/index.ts"],"sourcesContent":["import type { Status } from \"better-auth\";\nimport { APIError } from \"better-auth\";\nimport { statusCodes } from \"better-call\";\n\n/**\n * SCIM compliant error\n * See: https://datatracker.ietf.org/doc/html/rfc7644#section-3.12\n */\nexport class SCIMAPIError extends APIError {\n\tconstructor(\n\t\tstatus: keyof typeof statusCodes | Status = \"INTERNAL_SERVER_ERROR\",\n\t\toverrides: any = {},\n\t) {\n\t\tconst body = {\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:Error\"],\n\t\t\tstatus: (typeof status === \"number\"\n\t\t\t\t? status\n\t\t\t\t: statusCodes[status]\n\t\t\t).toString(),\n\t\t\tdetail: overrides.detail,\n\t\t\t...overrides,\n\t\t};\n\t\tsuper(status, body);\n\t\tthis.message = body.detail ?? body.message;\n\t}\n}\n\nconst SCIMErrorOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tstatus: {\n\t\t\ttype: \"string\",\n\t\t},\n\t\tdetail: {\n\t\t\ttype: \"string\",\n\t\t},\n\t\tscimType: {\n\t\t\ttype: \"string\",\n\t\t},\n\t},\n} as const;\n\nexport const SCIMErrorOpenAPISchemas = {\n\t\"400\": {\n\t\tdescription:\n\t\t\t\"Bad Request. Usually due to missing parameters, or invalid parameters\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"401\": {\n\t\tdescription: \"Unauthorized. Due to missing or invalid authentication.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"403\": {\n\t\tdescription: \"Unauthorized. Due to missing or invalid authentication.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"404\": {\n\t\tdescription: \"Not Found. The requested resource was not found.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"429\": {\n\t\tdescription:\n\t\t\t\"Too Many Requests. You have exceeded the rate limit. Try again later.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"500\": {\n\t\tdescription:\n\t\t\t\"Internal Server Error. This is a problem with the server that you cannot fix.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n};\n","import type { GenericEndpointContext } from \"better-auth\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport { defaultKeyHasher } from \"better-auth/plugins\";\nimport type { SCIMOptions } from \"./types\";\n\nexport async function storeSCIMToken(\n\tctx: GenericEndpointContext,\n\topts: SCIMOptions,\n\tscimToken: string,\n) {\n\tif (opts.storeSCIMToken === \"encrypted\") {\n\t\treturn await symmetricEncrypt({\n\t\t\tkey: ctx.context.secret,\n\t\t\tdata: scimToken,\n\t\t});\n\t}\n\tif (opts.storeSCIMToken === \"hashed\") {\n\t\treturn await defaultKeyHasher(scimToken);\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"hash\" in opts.storeSCIMToken\n\t) {\n\t\treturn await opts.storeSCIMToken.hash(scimToken);\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"encrypt\" in opts.storeSCIMToken\n\t) {\n\t\treturn await opts.storeSCIMToken.encrypt(scimToken);\n\t}\n\n\treturn scimToken;\n}\n\nexport async function verifySCIMToken(\n\tctx: GenericEndpointContext,\n\topts: SCIMOptions,\n\tstoredSCIMToken: string,\n\tscimToken: string,\n): Promise<boolean> {\n\tif (opts.storeSCIMToken === \"encrypted\") {\n\t\treturn (\n\t\t\t(await symmetricDecrypt({\n\t\t\t\tkey: ctx.context.secret,\n\t\t\t\tdata: storedSCIMToken,\n\t\t\t})) === scimToken\n\t\t);\n\t}\n\tif (opts.storeSCIMToken === \"hashed\") {\n\t\tconst hashedSCIMToken = await defaultKeyHasher(scimToken);\n\t\treturn hashedSCIMToken === storedSCIMToken;\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"hash\" in opts.storeSCIMToken\n\t) {\n\t\tconst hashedSCIMToken = await opts.storeSCIMToken.hash(scimToken);\n\t\treturn hashedSCIMToken === storedSCIMToken;\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"decrypt\" in opts.storeSCIMToken\n\t) {\n\t\tconst decryptedSCIMToken =\n\t\t\tawait opts.storeSCIMToken.decrypt(storedSCIMToken);\n\t\treturn decryptedSCIMToken === scimToken;\n\t}\n\n\treturn scimToken === storedSCIMToken;\n}\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport { createAuthMiddleware } from \"better-auth/api\";\nimport { SCIMAPIError } from \"./scim-error\";\nimport { verifySCIMToken } from \"./scim-tokens\";\nimport type { SCIMOptions, SCIMProvider } from \"./types\";\n\nexport type AuthMiddleware = ReturnType<typeof authMiddlewareFactory>;\n\n/**\n * The middleware forces the endpoint to have a valid token\n */\nexport const authMiddlewareFactory = (opts: SCIMOptions) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tconst authHeader = ctx.headers?.get(\"Authorization\");\n\t\tconst authSCIMToken = authHeader?.replace(/^Bearer\\s+/i, \"\");\n\n\t\tif (!authSCIMToken) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"SCIM token is required\",\n\t\t\t});\n\t\t}\n\n\t\tconst baseScimTokenParts = new TextDecoder()\n\t\t\t.decode(base64Url.decode(authSCIMToken))\n\t\t\t.split(\":\");\n\n\t\tconst [scimToken, providerId] = baseScimTokenParts;\n\t\tconst organizationId = baseScimTokenParts.slice(2).join(\":\");\n\n\t\tif (!scimToken || !providerId) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\tlet scimProvider: Omit<SCIMProvider, \"id\"> | null =\n\t\t\topts.defaultSCIM?.find((p) => {\n\t\t\t\tif (p.providerId === providerId && !organizationId) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn !!(\n\t\t\t\t\tp.providerId === providerId &&\n\t\t\t\t\torganizationId &&\n\t\t\t\t\tp.organizationId === organizationId\n\t\t\t\t);\n\t\t\t}) ?? null;\n\n\t\tif (scimProvider) {\n\t\t\tif (scimProvider.scimToken === scimToken) {\n\t\t\t\treturn { authSCIMToken: scimProvider.scimToken, scimProvider };\n\t\t\t} else {\n\t\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tscimProvider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\t\tmodel: \"scimProvider\",\n\t\t\twhere: [\n\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t...(organizationId\n\t\t\t\t\t? [{ field: \"organizationId\", value: organizationId }]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t});\n\n\t\tif (!scimProvider) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\tconst isValidToken = await verifySCIMToken(\n\t\t\tctx,\n\t\t\topts,\n\t\t\tscimProvider.scimToken,\n\t\t\tscimToken,\n\t\t);\n\n\t\tif (!isValidToken) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\treturn { authSCIMToken: scimToken, scimProvider };\n\t});\n","import type { SCIMEmail, SCIMName } from \"./types\";\n\nexport const getAccountId = (userName: string, externalId?: string) => {\n\treturn externalId ?? userName;\n};\n\nconst getFormattedName = (name: SCIMName): string | undefined => {\n\tif (name.givenName && name.familyName) {\n\t\treturn `${name.givenName} ${name.familyName}`;\n\t}\n\tif (name.givenName) {\n\t\treturn name.givenName;\n\t}\n\treturn name.familyName;\n};\n\nexport const getUserFullName = (name?: SCIMName): string | undefined => {\n\tif (!name) {\n\t\treturn undefined;\n\t}\n\tconst formatted = name.formatted?.trim();\n\tif (formatted) {\n\t\treturn formatted;\n\t}\n\treturn getFormattedName(name);\n};\n\nexport const getUserPrimaryEmail = (userName: string, emails?: SCIMEmail[]) => {\n\treturn (\n\t\temails?.find((email) => email.primary)?.value ??\n\t\temails?.[0]?.value ??\n\t\tuserName\n\t);\n};\n","import type { User } from \"better-auth\";\nimport { getUserFullName } from \"./mappings\";\n\ntype Operation = {\n\top: \"add\" | \"remove\" | \"replace\";\n\tvalue: any;\n\tpath?: string;\n};\n\ntype Mapping = {\n\ttarget: string;\n\tresource: \"user\" | \"account\";\n\tmap: (user: User, op: Operation, resources: Resources) => any;\n};\n\ntype Resources = {\n\tuser: Record<string, any>;\n\taccount: Record<string, any>;\n};\n\nconst identity = (user: User, op: Operation, resources: Resources) => {\n\treturn op.value;\n};\n\nconst lowerCase = (user: User, op: Operation, resources: Resources) => {\n\treturn op.value.toLowerCase();\n};\n\nconst givenName = (user: User, op: Operation, resources: Resources) => {\n\tconst currentName =\n\t\t(resources.user.name as string | null | undefined) ?? user.name;\n\tconst familyName = currentName?.split(\" \").slice(1).join(\" \").trim();\n\tconst givenName = op.value;\n\n\treturn getUserFullName({\n\t\tgivenName,\n\t\tfamilyName,\n\t});\n};\n\nconst familyName = (user: User, op: Operation, resources: Resources) => {\n\tconst currentName =\n\t\t(resources.user.name as string | null | undefined) ?? user.name;\n\tconst givenName = currentName\n\t\t? (currentName.split(\" \").slice(0, -1).join(\" \") || currentName).trim()\n\t\t: undefined;\n\tconst familyName = op.value;\n\treturn getUserFullName({\n\t\tgivenName,\n\t\tfamilyName,\n\t});\n};\n\nconst userPatchMappings: Record<string, Mapping> = {\n\t\"/name/formatted\": { resource: \"user\", target: \"name\", map: identity },\n\t\"/name/givenName\": { resource: \"user\", target: \"name\", map: givenName },\n\t\"/name/familyName\": {\n\t\tresource: \"user\",\n\t\ttarget: \"name\",\n\t\tmap: familyName,\n\t},\n\t\"/externalId\": {\n\t\tresource: \"account\",\n\t\ttarget: \"accountId\",\n\t\tmap: identity,\n\t},\n\t\"/userName\": { resource: \"user\", target: \"email\", map: lowerCase },\n};\n\nconst normalizePath = (path: string): string => {\n\tconst withoutLeadingSlash = path.startsWith(\"/\") ? path.slice(1) : path;\n\treturn `/${withoutLeadingSlash.replaceAll(\".\", \"/\")}`;\n};\n\nconst isNestedObject = (value: unknown): value is Record<string, unknown> => {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst applyMapping = (\n\tuser: User,\n\tresources: Resources,\n\tpath: string,\n\tvalue: unknown,\n\top: \"add\" | \"replace\",\n) => {\n\tconst normalizedPath = normalizePath(path);\n\tconst mapping = userPatchMappings[normalizedPath];\n\n\tif (!mapping) {\n\t\treturn;\n\t}\n\n\tconst newValue = mapping.map(\n\t\tuser,\n\t\t{\n\t\t\top,\n\t\t\tvalue,\n\t\t\tpath: normalizedPath,\n\t\t},\n\t\tresources,\n\t);\n\n\tif (op === \"add\" && mapping.resource === \"user\") {\n\t\tconst currentValue = (user as Record<string, unknown>)[mapping.target];\n\t\tif (currentValue === newValue) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tresources[mapping.resource][mapping.target] = newValue;\n};\n\nconst applyPatchValue = (\n\tuser: User,\n\tresources: Resources,\n\tvalue: unknown,\n\top: \"add\" | \"replace\",\n\tpath?: string | undefined,\n) => {\n\tif (isNestedObject(value)) {\n\t\tfor (const [key, nestedValue] of Object.entries(value)) {\n\t\t\tconst nestedPath = path ? `${path}.${key}` : key;\n\t\t\tapplyPatchValue(user, resources, nestedValue, op, nestedPath);\n\t\t}\n\t} else if (path) {\n\t\tapplyMapping(user, resources, path, value, op);\n\t}\n};\n\nexport const buildUserPatch = (user: User, operations: Operation[]) => {\n\tconst userPatch: Record<string, any> = {};\n\tconst accountPatch: Record<string, any> = {};\n\tconst resources: Resources = { user: userPatch, account: accountPatch };\n\n\tfor (const operation of operations) {\n\t\tif (operation.op !== \"add\" && operation.op !== \"replace\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tapplyPatchValue(\n\t\t\tuser,\n\t\t\tresources,\n\t\t\toperation.value,\n\t\t\toperation.op,\n\t\t\toperation.path,\n\t\t);\n\t}\n\n\treturn resources;\n};\n","import * as z from \"zod\";\n\nexport const APIUserSchema = z.object({\n\tuserName: z.string().lowercase(),\n\texternalId: z.string().optional(),\n\tname: z\n\t\t.object({\n\t\t\tformatted: z.string().optional(),\n\t\t\tgivenName: z.string().optional(),\n\t\t\tfamilyName: z.string().optional(),\n\t\t})\n\t\t.optional(),\n\temails: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tvalue: z.email(),\n\t\t\t\tprimary: z.boolean().optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\nexport const OpenAPIUserResourceSchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tid: { type: \"string\" },\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tcreated: { type: \"string\", format: \"date-time\" },\n\t\t\t\tlastModified: { type: \"string\", format: \"date-time\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tuserName: { type: \"string\" },\n\t\tname: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tformatted: { type: \"string\" },\n\t\t\t\tgivenName: { type: \"string\" },\n\t\t\t\tfamilyName: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tdisplayName: { type: \"string\" },\n\t\tactive: { type: \"boolean\" },\n\t\temails: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\tvalue: { type: \"string\" },\n\t\t\t\t\tprimary: { type: \"boolean\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t},\n} as const;\n\nexport const SCIMUserResourceSchema = {\n\tid: \"urn:ietf:params:scim:schemas:core:2.0:User\",\n\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:Schema\"],\n\tname: \"User\",\n\tdescription: \"User Account\",\n\tattributes: [\n\t\t{\n\t\t\tname: \"id\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription: \"Unique opaque identifier for the User\",\n\t\t\trequired: false,\n\t\t\tcaseExact: true,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"server\",\n\t\t},\n\t\t{\n\t\t\tname: \"userName\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"Unique identifier for the User, typically used by the user to directly authenticate to the service provider\",\n\t\t\trequired: true,\n\t\t\tcaseExact: false,\n\t\t\tmutability: \"readWrite\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"server\",\n\t\t},\n\t\t{\n\t\t\tname: \"displayName\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"The name of the User, suitable for display to end-users. The name SHOULD be the full name of the User being described, if known.\",\n\t\t\trequired: false,\n\t\t\tcaseExact: true,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"none\",\n\t\t},\n\t\t{\n\t\t\tname: \"active\",\n\t\t\ttype: \"boolean\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"A Boolean value indicating the User's administrative status.\",\n\t\t\trequired: false,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t},\n\t\t{\n\t\t\tname: \"name\",\n\t\t\ttype: \"complex\",\n\t\t\tmultiValued: false,\n\t\t\tdescription: \"The components of the user's real name.\",\n\t\t\trequired: false,\n\t\t\tsubAttributes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"formatted\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The full name, including all middlenames, titles, and suffixes as appropriate, formatted for display(e.g., 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"familyName\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The family name of the User, or last name in most Western languages (e.g., 'Jensen' given the fullname 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"givenName\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The given name of the User, or first name in most Western languages (e.g., 'Barbara' given the full name 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tname: \"emails\",\n\t\t\ttype: \"complex\",\n\t\t\tmultiValued: true,\n\t\t\tdescription:\n\t\t\t\t\"Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.\",\n\t\t\trequired: false,\n\t\t\tsubAttributes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"server\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"primary\",\n\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address. The primary attribute value 'true' MUST appear no more than once.\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tmutability: \"readWrite\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"none\",\n\t\t},\n\t],\n\tmeta: {\n\t\tresourceType: \"Schema\",\n\t\tlocation: \"/scim/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User\",\n\t},\n};\n\nexport const SCIMUserResourceType = {\n\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:ResourceType\"],\n\tid: \"User\",\n\tname: \"User\",\n\tendpoint: \"/Users\",\n\tdescription: \"User Account\",\n\tschema: \"urn:ietf:params:scim:schemas:core:2.0:User\",\n\tmeta: {\n\t\tresourceType: \"ResourceType\",\n\t\tlocation: \"/scim/v2/ResourceTypes/User\",\n\t},\n};\n","import { SCIMUserResourceSchema } from \"./user-schemas\";\n\nexport type DBFilter = {\n\tfield: string;\n\tvalue: string | string[];\n\toperator?: any;\n};\n\nconst SCIMOperators: Record<string, string | undefined> = {\n\teq: \"eq\",\n};\n\nconst SCIMUserAttributes: Record<string, string | undefined> = {\n\tuserName: \"email\",\n};\n\nexport class SCIMParseError extends Error {}\n\nconst SCIMFilterRegex =\n\t/^\\s*(?<attribute>[^\\s]+)\\s+(?<op>eq|ne|co|sw|ew|pr)\\s*(?:(?<value>\"[^\"]*\"|[^\\s]+))?\\s*$/i;\n\nconst parseSCIMFilter = (filter: string) => {\n\tconst match = filter.match(SCIMFilterRegex);\n\tif (!match) {\n\t\tthrow new SCIMParseError(\"Invalid filter expression\");\n\t}\n\n\tconst attribute = match.groups?.attribute;\n\tconst op = match.groups?.op?.toLowerCase();\n\tconst value = match.groups?.value;\n\n\tif (!attribute || !op || !value) {\n\t\tthrow new SCIMParseError(\"Invalid filter expression\");\n\t}\n\n\tconst operator = SCIMOperators[op];\n\tif (!operator) {\n\t\tthrow new SCIMParseError(`The operator \"${op}\" is not supported`);\n\t}\n\n\treturn { attribute, operator, value };\n};\n\nexport const parseSCIMUserFilter = (filter: string) => {\n\tconst { attribute, operator, value } = parseSCIMFilter(filter);\n\n\tconst filters: DBFilter[] = [];\n\tconst targetAttribute = SCIMUserAttributes[attribute];\n\tconst resourceAttribute = SCIMUserResourceSchema.attributes.find(\n\t\t(attr) => attr.name === attribute,\n\t);\n\n\tif (!targetAttribute || !resourceAttribute) {\n\t\tthrow new SCIMParseError(`The attribute \"${attribute}\" is not supported`);\n\t}\n\n\tlet finalValue = value.replaceAll('\"', \"\");\n\tif (!resourceAttribute.caseExact) {\n\t\tfinalValue = finalValue.toLowerCase();\n\t}\n\n\tfilters.push({\n\t\tfield: targetAttribute,\n\t\tvalue: finalValue,\n\t\toperator,\n\t});\n\n\treturn filters;\n};\n","const MetadataFieldSupportOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tsupported: {\n\t\t\ttype: \"boolean\",\n\t\t},\n\t},\n};\n\nexport const ServiceProviderOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tpatch: MetadataFieldSupportOpenAPISchema,\n\t\tbulk: MetadataFieldSupportOpenAPISchema,\n\t\tfilter: MetadataFieldSupportOpenAPISchema,\n\t\tchangePassword: MetadataFieldSupportOpenAPISchema,\n\t\tsort: MetadataFieldSupportOpenAPISchema,\n\t\tetag: MetadataFieldSupportOpenAPISchema,\n\t\tauthenticationSchemes: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tdescription: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tspecUri: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\ttype: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tprimary: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"string\",\n\t\t\t},\n\t\t},\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nexport const ResourceTypeOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tid: { type: \"string\" },\n\t\tname: { type: \"string\" },\n\t\tendpoint: { type: \"string\" },\n\t\tdescription: { type: \"string\" },\n\t\tschema: { type: \"string\" },\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nconst SCIMSchemaAttributesOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tname: { type: \"string\" },\n\t\ttype: { type: \"string\" },\n\t\tmultiValued: { type: \"boolean\" },\n\t\tdescription: { type: \"string\" },\n\t\trequired: { type: \"boolean\" },\n\t\tcaseExact: { type: \"boolean\" },\n\t\tmutability: { type: \"string\" },\n\t\treturned: { type: \"string\" },\n\t\tuniqueness: { type: \"string\" },\n\t},\n} as const;\n\nexport const SCIMSchemaOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tid: { type: \"string\" },\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tname: { type: \"string\" },\n\t\tdescription: { type: \"string\" },\n\t\tattributes: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\t...SCIMSchemaAttributesOpenAPISchema,\n\t\t\t\tproperties: {\n\t\t\t\t\t...SCIMSchemaAttributesOpenAPISchema.properties,\n\t\t\t\t\tsubAttributes: {\n\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\titems: SCIMSchemaAttributesOpenAPISchema,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"resourceType\", \"location\"],\n\t\t},\n\t},\n} as const;\n","export const getResourceURL = (path: string, baseURL: string) => {\n\tconst normalizedBaseURL = baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`;\n\tconst normalizedPath = path.replace(/^\\/+/, \"\");\n\treturn new URL(normalizedPath, normalizedBaseURL).toString();\n};\n","import type { Account, User } from \"better-auth\";\nimport { SCIMUserResourceSchema } from \"./user-schemas\";\nimport { getResourceURL } from \"./utils\";\n\nexport const createUserResource = (\n\tbaseURL: string,\n\tuser: User,\n\taccount?: Account | null,\n) => {\n\treturn {\n\t\t// Common attributes\n\t\t// See https://datatracker.ietf.org/doc/html/rfc7643#section-3.1\n\n\t\tid: user.id,\n\t\texternalId: account?.accountId,\n\t\tmeta: {\n\t\t\tresourceType: \"User\",\n\t\t\tcreated: user.createdAt,\n\t\t\tlastModified: user.updatedAt,\n\t\t\tlocation: getResourceURL(`/scim/v2/Users/${user.id}`, baseURL),\n\t\t},\n\n\t\t// SCIM user resource\n\t\t// See https://datatracker.ietf.org/doc/html/rfc7643#section-4.1\n\n\t\tuserName: user.email,\n\t\tname: user.name ? { formatted: user.name } : undefined,\n\t\tdisplayName: user.name ?? undefined,\n\t\tactive: true,\n\t\temails: [{ primary: true, value: user.email }],\n\t\tschemas: [SCIMUserResourceSchema.id],\n\t};\n};\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport type { Account, DBAdapter, User } from \"better-auth\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport {\n\tAPIError,\n\tcreateAuthEndpoint,\n\tsessionMiddleware,\n} from \"better-auth/api\";\nimport { generateRandomString } from \"better-auth/crypto\";\nimport type { Member } from \"better-auth/plugins\";\nimport * as z from \"zod\";\nimport { getAccountId, getUserFullName, getUserPrimaryEmail } from \"./mappings\";\nimport type { AuthMiddleware } from \"./middlewares\";\nimport { buildUserPatch } from \"./patch-operations\";\nimport { SCIMAPIError, SCIMErrorOpenAPISchemas } from \"./scim-error\";\nimport type { DBFilter } from \"./scim-filters\";\nimport { parseSCIMUserFilter, SCIMParseError } from \"./scim-filters\";\nimport {\n\tResourceTypeOpenAPISchema,\n\tSCIMSchemaOpenAPISchema,\n\tServiceProviderOpenAPISchema,\n} from \"./scim-metadata\";\nimport { createUserResource } from \"./scim-resources\";\nimport { storeSCIMToken } from \"./scim-tokens\";\nimport type { SCIMOptions, SCIMProvider } from \"./types\";\nimport {\n\tAPIUserSchema,\n\tOpenAPIUserResourceSchema,\n\tSCIMUserResourceSchema,\n\tSCIMUserResourceType,\n} from \"./user-schemas\";\nimport { getResourceURL } from \"./utils\";\n\nconst supportedSCIMSchemas = [SCIMUserResourceSchema];\nconst supportedSCIMResourceTypes = [SCIMUserResourceType];\nconst supportedMediaTypes = [\"application/json\", \"application/scim+json\"];\n\nconst generateSCIMTokenBodySchema = z.object({\n\tproviderId: z.string().meta({ description: \"Unique provider identifier\" }),\n\torganizationId: z\n\t\t.string()\n\t\t.optional()\n\t\t.meta({ description: \"Optional organization id\" }),\n});\n\nexport const generateSCIMToken = (opts: SCIMOptions) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/generate-token\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: generateSCIMTokenBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Generates a new SCIM token for the given provider\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Generates a new SCIM token to be used for SCIM operations\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\tdescription: \"SCIM token response\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tscimToken: {\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"SCIM token\",\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { providerId, organizationId } = ctx.body;\n\t\t\tconst user = ctx.context.session.user;\n\n\t\t\tif (providerId.includes(\":\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Provider id contains forbidden characters\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (organizationId && !ctx.context.hasPlugin(\"organization\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"Restricting a token to an organization requires the organization plugin\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet member: Member | null = null;\n\t\t\tif (organizationId) {\n\t\t\t\tmember = await ctx.context.adapter.findOne<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\t\tvalue: organizationId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (!member) {\n\t\t\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\t\t\tmessage: \"You are not a member of the organization\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst scimProvider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t\t...(organizationId\n\t\t\t\t\t\t? [{ field: \"organizationId\", value: organizationId }]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (scimProvider) {\n\t\t\t\tawait ctx.context.adapter.delete<SCIMProvider>({\n\t\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\t\twhere: [{ field: \"id\", value: scimProvider.id }],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst baseToken = generateRandomString(24);\n\t\t\tconst scimToken = base64Url.encode(\n\t\t\t\t`${baseToken}:${providerId}${organizationId ? `:${organizationId}` : \"\"}`,\n\t\t\t);\n\n\t\t\tif (opts.beforeSCIMTokenGenerated) {\n\t\t\t\tawait opts.beforeSCIMTokenGenerated({\n\t\t\t\t\tuser,\n\t\t\t\t\tmember,\n\t\t\t\t\tscimToken,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst newSCIMProvider = await ctx.context.adapter.create<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\tdata: {\n\t\t\t\t\tproviderId: providerId,\n\t\t\t\t\torganizationId: organizationId,\n\t\t\t\t\tscimToken: await storeSCIMToken(ctx, opts, baseToken),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (opts.afterSCIMTokenGenerated) {\n\t\t\t\tawait opts.afterSCIMTokenGenerated({\n\t\t\t\t\tuser,\n\t\t\t\t\tmember,\n\t\t\t\t\tscimToken,\n\t\t\t\t\tscimProvider: newSCIMProvider,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tctx.setStatus(201);\n\n\t\t\treturn ctx.json({\n\t\t\t\tscimToken,\n\t\t\t});\n\t\t},\n\t);\n\nexport const createSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: APIUserSchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Create SCIM user.\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Provision a new user into the linked organization via SCIM. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.3\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst accountId = getAccountId(body.userName, body.externalId);\n\n\t\t\tconst existingAccount = await ctx.context.adapter.findOne<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"accountId\", value: accountId },\n\t\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (existingAccount) {\n\t\t\t\tthrow new SCIMAPIError(\"CONFLICT\", {\n\t\t\t\t\tdetail: \"User already exists\",\n\t\t\t\t\tscimType: \"uniqueness\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst email = getUserPrimaryEmail(body.userName, body.emails);\n\t\t\tconst name = getUserFullName(body.name);\n\n\t\t\tconst existingUser = await ctx.context.adapter.findOne<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [{ field: \"email\", value: email }],\n\t\t\t});\n\n\t\t\tconst createAccount = (userId: string) =>\n\t\t\t\tctx.context.internalAdapter.createAccount({\n\t\t\t\t\tuserId: userId,\n\t\t\t\t\tproviderId: providerId,\n\t\t\t\t\taccountId: accountId,\n\t\t\t\t\taccessToken: \"\",\n\t\t\t\t\trefreshToken: \"\",\n\t\t\t\t});\n\n\t\t\tconst createUser = () =>\n\t\t\t\tctx.context.internalAdapter.createUser({\n\t\t\t\t\temail,\n\t\t\t\t\tname,\n\t\t\t\t});\n\n\t\t\tconst createOrgMembership = async (userId: string) => {\n\t\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\t\tif (organizationId) {\n\t\t\t\t\tconst isOrgMember = await ctx.context.adapter.findOne({\n\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t\t\t\t{ field: \"userId\", value: userId },\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!isOrgMember) {\n\t\t\t\t\t\treturn await ctx.context.adapter.create<Member>({\n\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tuserId: userId,\n\t\t\t\t\t\t\t\trole: \"member\",\n\t\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t\t\torganizationId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tlet user: User;\n\t\t\tlet account: Account;\n\n\t\t\tif (existingUser) {\n\t\t\t\tuser = existingUser;\n\t\t\t\taccount = await ctx.context.adapter.transaction<Account>(async () => {\n\t\t\t\t\tconst account = await createAccount(user.id);\n\t\t\t\t\tawait createOrgMembership(user.id);\n\t\t\t\t\treturn account;\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t[user, account] = await ctx.context.adapter.transaction<\n\t\t\t\t\t[User, Account]\n\t\t\t\t>(async () => {\n\t\t\t\t\tconst user = await createUser();\n\t\t\t\t\tconst account = await createAccount(user.id);\n\t\t\t\t\tawait createOrgMembership(user.id);\n\t\t\t\t\treturn [user, account];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst userResource = createUserResource(\n\t\t\t\tctx.context.baseURL,\n\t\t\t\tuser,\n\t\t\t\taccount,\n\t\t\t);\n\n\t\t\tctx.setStatus(201);\n\t\t\tctx.setHeader(\"location\", userResource.meta.location);\n\t\t\treturn ctx.json(userResource);\n\t\t},\n\t);\n\nexport const updateSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"PUT\",\n\t\t\tbody: APIUserSchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Update SCIM user.\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Updates an existing user into the linked organization via SCIM. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.3\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body;\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst { organizationId, providerId } = ctx.context.scimProvider;\n\t\t\tconst accountId = getAccountId(body.userName, body.externalId);\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst [updatedUser, updatedAccount] =\n\t\t\t\tawait ctx.context.adapter.transaction<[User | null, Account | null]>(\n\t\t\t\t\tasync () => {\n\t\t\t\t\t\tconst email = getUserPrimaryEmail(body.userName, body.emails);\n\t\t\t\t\t\tconst name = getUserFullName(body.name);\n\n\t\t\t\t\t\tconst updatedUser = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\t\tuserId,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst updatedAccount =\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\t\t\t\t\t\taccountId,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn [updatedUser, updatedAccount];\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\tconst userResource = createUserResource(\n\t\t\t\tctx.context.baseURL,\n\t\t\t\tupdatedUser!,\n\t\t\t\tupdatedAccount,\n\t\t\t);\n\n\t\t\treturn ctx.json(userResource);\n\t\t},\n\t);\n\nconst listSCIMUsersQuerySchema = z\n\t.object({\n\t\tfilter: z.string().optional(),\n\t})\n\t.optional();\n\nexport const listSCIMUsers = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listSCIMUsersQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"List SCIM users\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns all users provisioned via SCIM for the linked organization. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user list\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttotalResults: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\titemsPerPage: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\tstartIndex: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\tResources: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\titems: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst apiFilters: DBFilter[] = parseSCIMAPIUserFilter(ctx.query?.filter);\n\n\t\t\tctx.context.logger.info(\"Querying result with filters: \", apiFilters);\n\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst accounts = await ctx.context.adapter.findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [{ field: \"providerId\", value: providerId }],\n\t\t\t});\n\n\t\t\tconst accountUserIds = accounts.map((account) => account.userId);\n\t\t\tlet userFilters: DBFilter[] = [\n\t\t\t\t{ field: \"id\", value: accountUserIds, operator: \"in\" },\n\t\t\t];\n\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\t\t\tif (organizationId) {\n\t\t\t\tconst members = await ctx.context.adapter.findMany<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t\t\t{ field: \"userId\", value: accountUserIds, operator: \"in\" },\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tconst memberUserIds = members.map((member) => member.userId);\n\t\t\t\tuserFilters = [{ field: \"id\", value: memberUserIds, operator: \"in\" }];\n\t\t\t}\n\n\t\t\tconst users = await ctx.context.adapter.findMany<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [...userFilters, ...apiFilters],\n\t\t\t});\n\n\t\t\treturn ctx.json({\n\t\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\t\ttotalResults: users.length,\n\t\t\t\tstartIndex: 1,\n\t\t\t\titemsPerPage: users.length,\n\t\t\t\tResources: users.map((user) => {\n\t\t\t\t\tconst account = accounts.find((a) => a.userId === user.id);\n\t\t\t\t\treturn createUserResource(ctx.context.baseURL, user, account);\n\t\t\t\t}),\n\t\t\t});\n\t\t},\n\t);\n\nexport const getSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Get SCIM user details\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns the provisioned SCIM user details. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.1\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn ctx.json(createUserResource(ctx.context.baseURL, user, account));\n\t\t},\n\t);\n\nconst patchSCIMUserBodySchema = z.object({\n\tschemas: z\n\t\t.array(z.string())\n\t\t.refine(\n\t\t\t(s) => s.includes(\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"),\n\t\t\t{\n\t\t\t\tmessage: \"Invalid schemas for PatchOp\",\n\t\t\t},\n\t\t),\n\tOperations: z.array(\n\t\tz.object({\n\t\t\top: z\n\t\t\t\t.string()\n\t\t\t\t.toLowerCase()\n\t\t\t\t.default(\"replace\")\n\t\t\t\t.pipe(z.enum([\"replace\", \"add\", \"remove\"])),\n\t\t\tpath: z.string().optional(),\n\t\t\tvalue: z.any(),\n\t\t}),\n\t),\n});\n\nexport const patchSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"PATCH\",\n\t\t\tbody: patchSCIMUserBodySchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Patch SCIM user\",\n\t\t\t\t\tdescription: \"Updates fields on a SCIM user record\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"204\": {\n\t\t\t\t\t\t\tdescription: \"Patch update applied correctly\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst { user: userPatch, account: accountPatch } = buildUserPatch(\n\t\t\t\tuser,\n\t\t\t\tctx.body.Operations,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tObject.keys(userPatch).length === 0 &&\n\t\t\t\tObject.keys(accountPatch).length === 0\n\t\t\t) {\n\t\t\t\tthrow new SCIMAPIError(\"BAD_REQUEST\", {\n\t\t\t\t\tdetail: \"No valid fields to update\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait Promise.all([\n\t\t\t\tObject.keys(userPatch).length > 0\n\t\t\t\t\t? ctx.context.internalAdapter.updateUser(userId, {\n\t\t\t\t\t\t\t...userPatch,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(),\n\t\t\t\tObject.keys(accountPatch).length > 0\n\t\t\t\t\t? ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\t\t\t\t\t...accountPatch,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(),\n\t\t\t]);\n\n\t\t\tctx.setStatus(204);\n\t\t\treturn;\n\t\t},\n\t);\n\nexport const deleteSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"DELETE\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: [...supportedMediaTypes, \"\"],\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Delete SCIM user\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Deletes (or deactivates) a user within the linked organization.\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"204\": {\n\t\t\t\t\t\t\tdescription: \"Delete applied successfully\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\tconst { user } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait ctx.context.internalAdapter.deleteUser(userId);\n\n\t\t\tctx.setStatus(204);\n\t\t\treturn;\n\t\t},\n\t);\n\nexport const getSCIMServiceProviderConfig = createAuthEndpoint(\n\t\"/scim/v2/ServiceProviderConfig\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Configuration\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: ServiceProviderOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\tpatch: { supported: true },\n\t\t\tbulk: { supported: false },\n\t\t\tfilter: { supported: true },\n\t\t\tchangePassword: { supported: false },\n\t\t\tsort: { supported: false },\n\t\t\tetag: { supported: false },\n\t\t\tauthenticationSchemes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"OAuth Bearer Token\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Authentication scheme using the Authorization header with a bearer token tied to an organization.\",\n\t\t\t\t\tspecUri: \"http://www.rfc-editor.org/info/rfc6750\",\n\t\t\t\t\ttype: \"oauthbearertoken\",\n\t\t\t\t\tprimary: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\"],\n\t\t\tmeta: {\n\t\t\t\tresourceType: \"ServiceProviderConfig\",\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const getSCIMSchemas = createAuthEndpoint(\n\t\"/scim/v2/Schemas\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Configuration Schemas\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to acquire information about supported schemas. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\titems: SCIMSchemaOpenAPISchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\ttotalResults: supportedSCIMSchemas.length,\n\t\t\titemsPerPage: supportedSCIMSchemas.length,\n\t\t\tstartIndex: 1,\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\tResources: supportedSCIMSchemas.map((s) => {\n\t\t\t\treturn {\n\t\t\t\t\t...s,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\t...s.meta,\n\t\t\t\t\t\tlocation: getResourceURL(s.meta.location, ctx.context.baseURL),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t},\n);\n\nexport const getSCIMSchema = createAuthEndpoint(\n\t\"/scim/v2/Schemas/:schemaId\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM a Service Provider Configuration Schema\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to acquire information about a given schema. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: SCIMSchemaOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst schema = supportedSCIMSchemas.find(\n\t\t\t(s) => s.id === ctx.params.schemaId,\n\t\t);\n\n\t\tif (!schema) {\n\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\tdetail: \"Schema not found\",\n\t\t\t});\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\t...schema,\n\t\t\tmeta: {\n\t\t\t\t...schema.meta,\n\t\t\t\tlocation: getResourceURL(schema.meta.location, ctx.context.baseURL),\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const getSCIMResourceTypes = createAuthEndpoint(\n\t\"/scim/v2/ResourceTypes\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Supported Resource Types\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to get a list of server supported types. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttotalResults: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\titemsPerPage: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\tstartIndex: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\tResources: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\titems: ResourceTypeOpenAPISchema,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\ttotalResults: supportedSCIMResourceTypes.length,\n\t\t\titemsPerPage: supportedSCIMResourceTypes.length,\n\t\t\tstartIndex: 1,\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\tResources: supportedSCIMResourceTypes.map((s) => {\n\t\t\t\treturn {\n\t\t\t\t\t...s,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\t...s.meta,\n\t\t\t\t\t\tlocation: getResourceURL(s.meta.location, ctx.context.baseURL),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t},\n);\n\nexport const getSCIMResourceType = createAuthEndpoint(\n\t\"/scim/v2/ResourceTypes/:resourceTypeId\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Supported Resource Type\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to get a server supported type. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: ResourceTypeOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst resourceType = supportedSCIMResourceTypes.find(\n\t\t\t(s) => s.id === ctx.params.resourceTypeId,\n\t\t);\n\n\t\tif (!resourceType) {\n\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\tdetail: \"Resource type not found\",\n\t\t\t});\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\t...resourceType,\n\t\t\tmeta: {\n\t\t\t\t...resourceType.meta,\n\t\t\t\tlocation: getResourceURL(\n\t\t\t\t\tresourceType.meta.location,\n\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t},\n);\n\nconst findUserById = async (\n\tadapter: DBAdapter,\n\t{\n\t\tuserId,\n\t\tproviderId,\n\t\torganizationId,\n\t}: { userId: string; providerId: string; organizationId?: string },\n) => {\n\tconst account = await adapter.findOne<Account>({\n\t\tmodel: \"account\",\n\t\twhere: [\n\t\t\t{ field: \"userId\", value: userId },\n\t\t\t{ field: \"providerId\", value: providerId },\n\t\t],\n\t});\n\n\t// Disallows access to the resource\n\t// Account is not associated to the provider\n\n\tif (!account) {\n\t\treturn { user: null, account: null };\n\t}\n\n\tlet member: Member | null = null;\n\tif (organizationId) {\n\t\tmember = await adapter.findOne<Member>({\n\t\t\tmodel: \"member\",\n\t\t\twhere: [\n\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t{ field: \"userId\", value: userId },\n\t\t\t],\n\t\t});\n\t}\n\n\t// Disallows access to the resource\n\t// Token is restricted to an org and the member is not part of it\n\n\tif (organizationId && !member) {\n\t\treturn { user: null, account: null };\n\t}\n\n\tconst user = await adapter.findOne<User>({\n\t\tmodel: \"user\",\n\t\twhere: [{ field: \"id\", value: userId }],\n\t});\n\n\tif (!user) {\n\t\treturn { user: null, account: null };\n\t}\n\n\treturn { user, account };\n};\n\nconst parseSCIMAPIUserFilter = (filter?: string) => {\n\tlet filters: DBFilter[] = [];\n\n\ttry {\n\t\tfilters = filter ? parseSCIMUserFilter(filter) : [];\n\t} catch (error) {\n\t\tthrow new SCIMAPIError(\"BAD_REQUEST\", {\n\t\t\tdetail:\n\t\t\t\terror instanceof SCIMParseError ? error.message : \"Invalid SCIM filter\",\n\t\t\tscimType: \"invalidFilter\",\n\t\t});\n\t}\n\n\treturn filters;\n};\n","import type { BetterAuthPlugin } from \"better-auth\";\nimport { authMiddlewareFactory } from \"./middlewares\";\nimport {\n\tcreateSCIMUser,\n\tdeleteSCIMUser,\n\tgenerateSCIMToken,\n\tgetSCIMResourceType,\n\tgetSCIMResourceTypes,\n\tgetSCIMSchema,\n\tgetSCIMSchemas,\n\tgetSCIMServiceProviderConfig,\n\tgetSCIMUser,\n\tlistSCIMUsers,\n\tpatchSCIMUser,\n\tupdateSCIMUser,\n} from \"./routes\";\nimport type { SCIMOptions } from \"./types\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\tscim: {\n\t\t\tcreator: typeof scim;\n\t\t};\n\t}\n}\n\nexport const scim = (options?: SCIMOptions) => {\n\tconst opts = {\n\t\tstoreSCIMToken: \"plain\",\n\t\t...options,\n\t} satisfies SCIMOptions;\n\n\tconst authMiddleware = authMiddlewareFactory(opts);\n\n\treturn {\n\t\tid: \"scim\",\n\t\tendpoints: {\n\t\t\tgenerateSCIMToken: generateSCIMToken(opts),\n\t\t\tgetSCIMUser: getSCIMUser(authMiddleware),\n\t\t\tcreateSCIMUser: createSCIMUser(authMiddleware),\n\t\t\tpatchSCIMUser: patchSCIMUser(authMiddleware),\n\t\t\tdeleteSCIMUser: deleteSCIMUser(authMiddleware),\n\t\t\tupdateSCIMUser: updateSCIMUser(authMiddleware),\n\t\t\tlistSCIMUsers: listSCIMUsers(authMiddleware),\n\t\t\tgetSCIMServiceProviderConfig,\n\t\t\tgetSCIMSchemas,\n\t\t\tgetSCIMSchema,\n\t\t\tgetSCIMResourceTypes,\n\t\t\tgetSCIMResourceType,\n\t\t},\n\t\tschema: {\n\t\t\tscimProvider: {\n\t\t\t\tfields: {\n\t\t\t\t\tproviderId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\tscimToken: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\torganizationId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport * from \"./types\";\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@better-auth/scim",
3
3
  "author": "Jonathan Samines",
4
- "version": "1.5.0-beta.10",
4
+ "version": "1.5.0-beta.11",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
7
7
  "types": "dist/index.d.mts",
@@ -49,12 +49,12 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "tsdown": "^0.20.1",
52
- "@better-auth/core": "1.5.0-beta.10",
53
- "@better-auth/sso": "1.5.0-beta.10"
52
+ "@better-auth/core": "1.5.0-beta.11",
53
+ "@better-auth/sso": "1.5.0-beta.11"
54
54
  },
55
55
  "peerDependencies": {
56
- "@better-auth/core": "1.5.0-beta.10",
57
- "better-auth": "1.5.0-beta.10"
56
+ "@better-auth/core": "1.5.0-beta.11",
57
+ "better-auth": "1.5.0-beta.11"
58
58
  },
59
59
  "scripts": {
60
60
  "test": "vitest",
package/src/mappings.ts CHANGED
@@ -4,29 +4,25 @@ export const getAccountId = (userName: string, externalId?: string) => {
4
4
  return externalId ?? userName;
5
5
  };
6
6
 
7
- const getFormattedName = (name: SCIMName) => {
7
+ const getFormattedName = (name: SCIMName): string | undefined => {
8
8
  if (name.givenName && name.familyName) {
9
9
  return `${name.givenName} ${name.familyName}`;
10
10
  }
11
-
12
11
  if (name.givenName) {
13
12
  return name.givenName;
14
13
  }
15
-
16
- return name.familyName ?? "";
14
+ return name.familyName;
17
15
  };
18
16
 
19
- export const getUserFullName = (email: string, name?: SCIMName) => {
20
- if (name) {
21
- const formatted = name.formatted?.trim() ?? "";
22
- if (formatted.length > 0) {
23
- return formatted;
24
- }
25
-
26
- return getFormattedName(name) || email;
17
+ export const getUserFullName = (name?: SCIMName): string | undefined => {
18
+ if (!name) {
19
+ return undefined;
27
20
  }
28
-
29
- return email;
21
+ const formatted = name.formatted?.trim();
22
+ if (formatted) {
23
+ return formatted;
24
+ }
25
+ return getFormattedName(name);
30
26
  };
31
27
 
32
28
  export const getUserPrimaryEmail = (userName: string, emails?: SCIMEmail[]) => {
@@ -27,23 +27,25 @@ const lowerCase = (user: User, op: Operation, resources: Resources) => {
27
27
  };
28
28
 
29
29
  const givenName = (user: User, op: Operation, resources: Resources) => {
30
- const currentName = (resources.user.name as string) ?? user.name;
31
- const familyName = currentName.split(" ").slice(1).join(" ").trim();
30
+ const currentName =
31
+ (resources.user.name as string | null | undefined) ?? user.name;
32
+ const familyName = currentName?.split(" ").slice(1).join(" ").trim();
32
33
  const givenName = op.value;
33
34
 
34
- return getUserFullName(user.email, {
35
+ return getUserFullName({
35
36
  givenName,
36
37
  familyName,
37
38
  });
38
39
  };
39
40
 
40
41
  const familyName = (user: User, op: Operation, resources: Resources) => {
41
- const currentName = (resources.user.name as string) ?? user.name;
42
- const givenName = (
43
- currentName.split(" ").slice(0, -1).join(" ") || currentName
44
- ).trim();
42
+ const currentName =
43
+ (resources.user.name as string | null | undefined) ?? user.name;
44
+ const givenName = currentName
45
+ ? (currentName.split(" ").slice(0, -1).join(" ") || currentName).trim()
46
+ : undefined;
45
47
  const familyName = op.value;
46
- return getUserFullName(user.email, {
48
+ return getUserFullName({
47
49
  givenName,
48
50
  familyName,
49
51
  });
package/src/routes.ts CHANGED
@@ -221,7 +221,7 @@ export const createSCIMUser = (authMiddleware: AuthMiddleware) =>
221
221
  }
222
222
 
223
223
  const email = getUserPrimaryEmail(body.userName, body.emails);
224
- const name = getUserFullName(email, body.name);
224
+ const name = getUserFullName(body.name);
225
225
 
226
226
  const existingUser = await ctx.context.adapter.findOne<User>({
227
227
  model: "user",
@@ -352,7 +352,7 @@ export const updateSCIMUser = (authMiddleware: AuthMiddleware) =>
352
352
  await ctx.context.adapter.transaction<[User | null, Account | null]>(
353
353
  async () => {
354
354
  const email = getUserPrimaryEmail(body.userName, body.emails);
355
- const name = getUserFullName(email, body.name);
355
+ const name = getUserFullName(body.name);
356
356
 
357
357
  const updatedUser = await ctx.context.internalAdapter.updateUser(
358
358
  userId,
@@ -24,10 +24,8 @@ export const createUserResource = (
24
24
  // See https://datatracker.ietf.org/doc/html/rfc7643#section-4.1
25
25
 
26
26
  userName: user.email,
27
- name: {
28
- formatted: user.name,
29
- },
30
- displayName: user.name,
27
+ name: user.name ? { formatted: user.name } : undefined,
28
+ displayName: user.name ?? undefined,
31
29
  active: true,
32
30
  emails: [{ primary: true, value: user.email }],
33
31
  schemas: [SCIMUserResourceSchema.id],
package/src/scim.test.ts CHANGED
@@ -841,7 +841,6 @@ describe("SCIM", () => {
841
841
  const user = await response.json();
842
842
  expect(user).toMatchObject({
843
843
  active: true,
844
- displayName: "the-username",
845
844
  emails: [
846
845
  {
847
846
  primary: true,
@@ -856,14 +855,14 @@ describe("SCIM", () => {
856
855
  location: expect.stringContaining("/api/auth/scim/v2/Users/"),
857
856
  resourceType: "User",
858
857
  }),
859
- name: {
860
- formatted: "the-username",
861
- },
862
858
  schemas: expect.arrayContaining([
863
859
  "urn:ietf:params:scim:schemas:core:2.0:User",
864
860
  ]),
865
861
  userName: "the-username",
866
862
  });
863
+ // When no name is provided, displayName and name should be undefined
864
+ expect(user.displayName).toBeUndefined();
865
+ expect(user.name).toBeUndefined();
867
866
  });
868
867
 
869
868
  it("should create a new account linked to an existing user", async () => {
@@ -936,7 +935,6 @@ describe("SCIM", () => {
936
935
 
937
936
  expect(user).toMatchObject({
938
937
  active: true,
939
- displayName: "the-username",
940
938
  emails: [
941
939
  {
942
940
  primary: true,
@@ -951,14 +949,14 @@ describe("SCIM", () => {
951
949
  location: expect.stringContaining("/api/auth/scim/v2/Users/"),
952
950
  resourceType: "User",
953
951
  }),
954
- name: {
955
- formatted: "the-username",
956
- },
957
952
  schemas: expect.arrayContaining([
958
953
  "urn:ietf:params:scim:schemas:core:2.0:User",
959
954
  ]),
960
955
  userName: "the-username",
961
956
  });
957
+ // When no name is provided, displayName and name should be undefined
958
+ expect(user.displayName).toBeUndefined();
959
+ expect(user.name).toBeUndefined();
962
960
  });
963
961
 
964
962
  it("should create a new user with name parts", async () => {
@@ -1206,7 +1204,7 @@ describe("SCIM", () => {
1206
1204
  expect(user).toBeTruthy();
1207
1205
  expect(user.externalId).toBe("the-username");
1208
1206
  expect(user.userName).toBe("primary-email@test.com");
1209
- expect(user.name.formatted).toBe("Juan Perez");
1207
+ expect(user.name?.formatted).toBe("Juan Perez");
1210
1208
  expect(user.emails[0]?.value).toBe("primary-email@test.com");
1211
1209
 
1212
1210
  const updatedUser = await auth.api.updateSCIMUser({
@@ -1333,7 +1331,7 @@ describe("SCIM", () => {
1333
1331
  expect(user).toBeTruthy();
1334
1332
  expect(user.externalId).toBe("the-username");
1335
1333
  expect(user.userName).toBe("primary-email@test.com");
1336
- expect(user.name.formatted).toBe("Juan Perez");
1334
+ expect(user.name?.formatted).toBe("Juan Perez");
1337
1335
  expect(user.emails[0]?.value).toBe("primary-email@test.com");
1338
1336
 
1339
1337
  await auth.api.patchSCIMUser({
@@ -1409,7 +1407,7 @@ describe("SCIM", () => {
1409
1407
  expect(user).toBeTruthy();
1410
1408
  expect(user.externalId).toBe("the-username");
1411
1409
  expect(user.userName).toBe("primary-email@test.com");
1412
- expect(user.name.formatted).toBe("Juan Perez");
1410
+ expect(user.name?.formatted).toBe("Juan Perez");
1413
1411
  expect(user.emails[0]?.value).toBe("primary-email@test.com");
1414
1412
 
1415
1413
  await auth.api.patchSCIMUser({
@@ -1505,7 +1503,7 @@ describe("SCIM", () => {
1505
1503
  },
1506
1504
  });
1507
1505
 
1508
- expect(updatedUser.name.formatted).toBe("Updated Value");
1506
+ expect(updatedUser.name?.formatted).toBe("Updated Value");
1509
1507
  });
1510
1508
 
1511
1509
  it.each([
@@ -1559,7 +1557,7 @@ describe("SCIM", () => {
1559
1557
  },
1560
1558
  });
1561
1559
 
1562
- expect(updatedUser.name.formatted).toBe("Nested User");
1560
+ expect(updatedUser.name?.formatted).toBe("Nested User");
1563
1561
  expect(updatedUser.displayName).toBe("Nested User");
1564
1562
  expect(updatedUser.userName).toBe("nested-test-user-updated");
1565
1563
  });
@@ -1606,7 +1604,7 @@ describe("SCIM", () => {
1606
1604
  },
1607
1605
  });
1608
1606
 
1609
- expect(updatedUser.name.formatted).toBe("No Path Name");
1607
+ expect(updatedUser.name?.formatted).toBe("No Path Name");
1610
1608
  expect(updatedUser.userName).toBe("username");
1611
1609
  });
1612
1610
 
@@ -1646,7 +1644,7 @@ describe("SCIM", () => {
1646
1644
  },
1647
1645
  });
1648
1646
 
1649
- expect(updatedUser.name.formatted).toBe("User Dot");
1647
+ expect(updatedUser.name?.formatted).toBe("User Dot");
1650
1648
  expect(updatedUser.userName).toBe("username");
1651
1649
  });
1652
1650
 
@@ -1691,7 +1689,7 @@ describe("SCIM", () => {
1691
1689
  },
1692
1690
  });
1693
1691
 
1694
- expect(updatedUser.name.formatted).toBe("user-case");
1692
+ expect(updatedUser.name?.formatted).toBe("user-case");
1695
1693
  });
1696
1694
 
1697
1695
  it("should skip add operation when value already exists", async () => {