@absolutejs/auth 0.37.0 → 0.38.0

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.
package/dist/index.d.ts CHANGED
@@ -13418,6 +13418,76 @@ export declare const auth: <UserType>({ providersConfiguration, authorizeRoute,
13418
13418
  };
13419
13419
  };
13420
13420
  };
13421
+ } & {
13422
+ [x: string]: {
13423
+ get: {
13424
+ body: unknown;
13425
+ params: {};
13426
+ query: unknown;
13427
+ headers: unknown;
13428
+ response: {
13429
+ 200: Response;
13430
+ };
13431
+ };
13432
+ };
13433
+ } & {
13434
+ [x: string]: {
13435
+ get: {
13436
+ body: unknown;
13437
+ params: {
13438
+ id: string;
13439
+ };
13440
+ query: unknown;
13441
+ headers: unknown;
13442
+ response: {
13443
+ 200: Response;
13444
+ 422: {
13445
+ type: "validation";
13446
+ on: string;
13447
+ summary?: string;
13448
+ message?: string;
13449
+ found?: unknown;
13450
+ property?: string;
13451
+ expected?: string;
13452
+ };
13453
+ };
13454
+ };
13455
+ };
13456
+ } & {
13457
+ [x: string]: {
13458
+ get: {
13459
+ body: unknown;
13460
+ params: {};
13461
+ query: unknown;
13462
+ headers: unknown;
13463
+ response: {
13464
+ 200: Response;
13465
+ };
13466
+ };
13467
+ };
13468
+ } & {
13469
+ [x: string]: {
13470
+ get: {
13471
+ body: unknown;
13472
+ params: {
13473
+ id: string;
13474
+ };
13475
+ query: unknown;
13476
+ headers: unknown;
13477
+ response: {
13478
+ 200: Response;
13479
+ 422: {
13480
+ type: "validation";
13481
+ on: string;
13482
+ summary?: string;
13483
+ message?: string;
13484
+ found?: unknown;
13485
+ property?: string;
13486
+ expected?: string;
13487
+ };
13488
+ };
13489
+ };
13490
+ };
13421
13491
  }))) & ({} | {
13422
13492
  [x: string]: {
13423
13493
  post: {
@@ -15137,6 +15207,7 @@ export * from './sso/types';
15137
15207
  export * from './sso/config';
15138
15208
  export * from './scim/types';
15139
15209
  export * from './scim/config';
15210
+ export * from './scim/extensions';
15140
15211
  export { scimRoutes } from './scim/routes';
15141
15212
  export { createInMemoryScimTokenStore } from './scim/inMemoryScimTokenStore';
15142
15213
  export { createNeonScimTokenStore, createPostgresScimTokenStore, scimTokensTable } from './scim/postgresScimTokenStore';
package/dist/index.js CHANGED
@@ -8315,10 +8315,26 @@ var GROUP_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:Group";
8315
8315
  var LIST_SCHEMA = "urn:ietf:params:scim:api:messages:2.0:ListResponse";
8316
8316
  var ERROR_SCHEMA = "urn:ietf:params:scim:api:messages:2.0:Error";
8317
8317
  var SPC_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig";
8318
+ var RESOURCE_TYPE_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:ResourceType";
8318
8319
  var SCIM_CONTENT_TYPE = "application/scim+json";
8319
8320
  var FILTER_MAX_RESULTS = 200;
8320
8321
  var FILTER_PATTERN = /^\s*(\w[\w.]*)\s+eq\s+"([^"]*)"\s*$/u;
8321
- var toUserResource = (user, location) => {
8322
+ var mergeCustomSchemas = (resource, custom, map) => {
8323
+ if (custom === undefined || map === undefined)
8324
+ return;
8325
+ const extra = map.toScim(custom);
8326
+ for (const [key, value] of Object.entries(extra)) {
8327
+ resource[key] = value;
8328
+ }
8329
+ const extraSchemas = (map.schemas ?? []).map((schema) => schema.id);
8330
+ if (extraSchemas.length === 0)
8331
+ return;
8332
+ const { schemas } = resource;
8333
+ if (Array.isArray(schemas)) {
8334
+ resource.schemas = [...schemas, ...extraSchemas];
8335
+ }
8336
+ };
8337
+ var toUserResource = (user, location, map) => {
8322
8338
  const resource = {
8323
8339
  active: user.active,
8324
8340
  id: user.id,
@@ -8339,6 +8355,7 @@ var toUserResource = (user, location) => {
8339
8355
  if (user.email !== undefined) {
8340
8356
  resource.emails = [{ primary: true, value: user.email }];
8341
8357
  }
8358
+ mergeCustomSchemas(resource, user.custom, map);
8342
8359
  return resource;
8343
8360
  };
8344
8361
  var stringField = (source, field) => {
@@ -8353,7 +8370,7 @@ var primaryEmail = (emails) => {
8353
8370
  const flagged = emails.find((entry) => typeof entry === "object" && entry !== null && Reflect.get(entry, "primary") === true);
8354
8371
  return stringField(flagged ?? emails[0], "value");
8355
8372
  };
8356
- var parseUserInput = (body) => {
8373
+ var parseUserInput = (body, map) => {
8357
8374
  if (typeof body !== "object" || body === null)
8358
8375
  return;
8359
8376
  const userName = stringField(body, "userName");
@@ -8361,8 +8378,14 @@ var parseUserInput = (body) => {
8361
8378
  return;
8362
8379
  const active = Reflect.get(body, "active");
8363
8380
  const name = Reflect.get(body, "name");
8381
+ const bodyRecord = {};
8382
+ for (const key of Object.keys(body)) {
8383
+ bodyRecord[key] = Reflect.get(body, key);
8384
+ }
8385
+ const custom = map === undefined ? undefined : map.fromScim(bodyRecord);
8364
8386
  return {
8365
8387
  active: typeof active === "boolean" ? active : true,
8388
+ custom,
8366
8389
  displayName: stringField(body, "displayName"),
8367
8390
  email: primaryEmail(Reflect.get(body, "emails")),
8368
8391
  externalId: stringField(body, "externalId"),
@@ -8423,6 +8446,7 @@ var applyOperation = (target, operation) => {
8423
8446
  var applyPatch = (user, body) => {
8424
8447
  const next = {
8425
8448
  active: user.active,
8449
+ custom: user.custom,
8426
8450
  displayName: user.displayName,
8427
8451
  email: user.email,
8428
8452
  externalId: user.externalId,
@@ -8468,6 +8492,15 @@ var scimJson = (resource, httpStatus) => new Response(JSON.stringify(resource),
8468
8492
  status: httpStatus
8469
8493
  });
8470
8494
  var serviceProviderConfig = (location) => ({
8495
+ authenticationSchemes: [
8496
+ {
8497
+ description: "Authentication scheme using the OAuth Bearer Token Standard",
8498
+ name: "OAuth Bearer Token",
8499
+ primary: true,
8500
+ specUri: "https://www.rfc-editor.org/info/rfc6750",
8501
+ type: "oauthbearertoken"
8502
+ }
8503
+ ],
8471
8504
  bulk: { maxOperations: 0, maxPayloadSize: 0, supported: false },
8472
8505
  changePassword: { supported: false },
8473
8506
  etag: { supported: false },
@@ -8477,6 +8510,111 @@ var serviceProviderConfig = (location) => ({
8477
8510
  schemas: [SPC_SCHEMA],
8478
8511
  sort: { supported: false }
8479
8512
  });
8513
+ var CORE_USER_ATTRIBUTES = [
8514
+ { multiValued: false, name: "userName", required: true, type: "string" },
8515
+ { multiValued: false, name: "active", required: false, type: "boolean" },
8516
+ { multiValued: false, name: "displayName", required: false, type: "string" },
8517
+ { multiValued: false, name: "externalId", required: false, type: "string" },
8518
+ {
8519
+ multiValued: false,
8520
+ name: "name",
8521
+ required: false,
8522
+ subAttributes: [
8523
+ { multiValued: false, name: "givenName", required: false, type: "string" },
8524
+ { multiValued: false, name: "familyName", required: false, type: "string" }
8525
+ ],
8526
+ type: "complex"
8527
+ },
8528
+ {
8529
+ multiValued: true,
8530
+ name: "emails",
8531
+ required: false,
8532
+ subAttributes: [
8533
+ { multiValued: false, name: "value", required: false, type: "string" },
8534
+ { multiValued: false, name: "primary", required: false, type: "boolean" }
8535
+ ],
8536
+ type: "complex"
8537
+ }
8538
+ ];
8539
+ var CORE_GROUP_ATTRIBUTES = [
8540
+ { multiValued: false, name: "displayName", required: true, type: "string" },
8541
+ { multiValued: false, name: "externalId", required: false, type: "string" },
8542
+ {
8543
+ multiValued: true,
8544
+ name: "members",
8545
+ required: false,
8546
+ subAttributes: [
8547
+ { multiValued: false, name: "value", required: false, type: "string" },
8548
+ { multiValued: false, name: "display", required: false, type: "string" }
8549
+ ],
8550
+ type: "complex"
8551
+ }
8552
+ ];
8553
+ var CORE_USER_SCHEMA = {
8554
+ attributes: CORE_USER_ATTRIBUTES,
8555
+ description: "User Account",
8556
+ id: USER_SCHEMA,
8557
+ name: "User"
8558
+ };
8559
+ var CORE_GROUP_SCHEMA = {
8560
+ attributes: CORE_GROUP_ATTRIBUTES,
8561
+ description: "Group",
8562
+ id: GROUP_SCHEMA,
8563
+ name: "Group"
8564
+ };
8565
+ var schemaResource = (schema, location) => ({
8566
+ attributes: schema.attributes,
8567
+ description: schema.description ?? schema.name,
8568
+ id: schema.id,
8569
+ meta: { location, resourceType: "Schema" },
8570
+ name: schema.name
8571
+ });
8572
+ var schemaList = (location, extras = []) => {
8573
+ const all = [CORE_USER_SCHEMA, CORE_GROUP_SCHEMA, ...extras];
8574
+ const resources = all.map((schema) => schemaResource(schema, `${location}/${schema.id}`));
8575
+ return listResponse(resources);
8576
+ };
8577
+ var schemaOne = (location, id, extras = []) => {
8578
+ const all = [CORE_USER_SCHEMA, CORE_GROUP_SCHEMA, ...extras];
8579
+ const found = all.find((schema) => schema.id === id);
8580
+ if (found === undefined)
8581
+ return;
8582
+ return schemaResource(found, location);
8583
+ };
8584
+ var resourceTypeUser = (location, usersEndpoint, extensionSchemaIds) => ({
8585
+ description: "User Account",
8586
+ endpoint: usersEndpoint,
8587
+ id: "User",
8588
+ meta: { location, resourceType: "ResourceType" },
8589
+ name: "User",
8590
+ schema: USER_SCHEMA,
8591
+ schemaExtensions: extensionSchemaIds.map((schema) => ({
8592
+ required: false,
8593
+ schema
8594
+ })),
8595
+ schemas: [RESOURCE_TYPE_SCHEMA]
8596
+ });
8597
+ var resourceTypeGroup = (location, groupsEndpoint) => ({
8598
+ description: "Group",
8599
+ endpoint: groupsEndpoint,
8600
+ id: "Group",
8601
+ meta: { location, resourceType: "ResourceType" },
8602
+ name: "Group",
8603
+ schema: GROUP_SCHEMA,
8604
+ schemas: [RESOURCE_TYPE_SCHEMA]
8605
+ });
8606
+ var resourceTypeList = (location, usersEndpoint, groupsEndpoint, extras = []) => listResponse([
8607
+ resourceTypeUser(`${location}/User`, usersEndpoint, extras.map((schema) => schema.id)),
8608
+ resourceTypeGroup(`${location}/Group`, groupsEndpoint)
8609
+ ]);
8610
+ var resourceTypeOne = (location, id, usersEndpoint, groupsEndpoint, extras = []) => {
8611
+ if (id === "User") {
8612
+ return resourceTypeUser(location, usersEndpoint, extras.map((schema) => schema.id));
8613
+ }
8614
+ if (id === "Group")
8615
+ return resourceTypeGroup(location, groupsEndpoint);
8616
+ return;
8617
+ };
8480
8618
  var REMOVE_MEMBER_PATTERN = /^members\[\s*value\s+eq\s+"([^"]*)"\s*\]$/iu;
8481
8619
  var parseMembers = (value) => {
8482
8620
  if (!Array.isArray(value))
@@ -8577,6 +8715,7 @@ var SCIM_CONTENT_TYPE2 = "application/scim+json";
8577
8715
  var unauthorized = () => scimError(SCIM_UNAUTHORIZED, "Invalid or missing SCIM bearer token");
8578
8716
  var notImplemented = () => scimError(SCIM_NOT_IMPLEMENTED, "Group provisioning is not configured");
8579
8717
  var scimRoutes = ({
8718
+ customAttributes,
8580
8719
  getScimGroup,
8581
8720
  getScimUser,
8582
8721
  listScimGroups,
@@ -8595,8 +8734,17 @@ var scimRoutes = ({
8595
8734
  const groupsRoute = `${scimRoute}/Groups`;
8596
8735
  const groupRoute = `${scimRoute}/Groups/:id`;
8597
8736
  const spcRoute = `${scimRoute}/ServiceProviderConfig`;
8737
+ const schemasRoute = `${scimRoute}/Schemas`;
8738
+ const schemaRoute = `${scimRoute}/Schemas/:id`;
8739
+ const resourceTypesRoute = `${scimRoute}/ResourceTypes`;
8740
+ const resourceTypeRoute = `${scimRoute}/ResourceTypes/:id`;
8741
+ const extensionSchemas = customAttributes?.schemas ?? [];
8598
8742
  const userLocation = (requestUrl, id) => `${new URL(requestUrl).origin}${scimRoute}/Users/${id}`;
8599
8743
  const groupLocation = (requestUrl, id) => `${new URL(requestUrl).origin}${scimRoute}/Groups/${id}`;
8744
+ const schemasLocation = (requestUrl) => `${new URL(requestUrl).origin}${scimRoute}/Schemas`;
8745
+ const resourceTypesLocation = (requestUrl) => `${new URL(requestUrl).origin}${scimRoute}/ResourceTypes`;
8746
+ const usersEndpoint = `${scimRoute}/Users`;
8747
+ const groupsEndpoint = `${scimRoute}/Groups`;
8600
8748
  return new Elysia29().onParse(({ request }, contentType) => contentType === SCIM_CONTENT_TYPE2 ? request.json() : undefined).get(spcRoute, async ({ headers, request }) => {
8601
8749
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8602
8750
  if (organizationId === undefined)
@@ -8606,12 +8754,12 @@ var scimRoutes = ({
8606
8754
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8607
8755
  if (organizationId === undefined)
8608
8756
  return unauthorized();
8609
- const input = parseUserInput(body);
8757
+ const input = parseUserInput(body, customAttributes);
8610
8758
  if (input === undefined) {
8611
8759
  return scimError(SCIM_BAD_REQUEST, "Request body is not a valid SCIM User", "invalidValue");
8612
8760
  }
8613
8761
  const user = await onScimUserCreate({ input, organizationId });
8614
- return scimJson(toUserResource(user, userLocation(request.url, user.id)), SCIM_CREATED);
8762
+ return scimJson(toUserResource(user, userLocation(request.url, user.id), customAttributes), SCIM_CREATED);
8615
8763
  }).get(usersRoute, async ({ headers, query, request }) => {
8616
8764
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8617
8765
  if (organizationId === undefined)
@@ -8620,7 +8768,7 @@ var scimRoutes = ({
8620
8768
  filter: parseFilter(query.filter),
8621
8769
  organizationId
8622
8770
  });
8623
- const resources = users.map((user) => toUserResource(user, userLocation(request.url, user.id)));
8771
+ const resources = users.map((user) => toUserResource(user, userLocation(request.url, user.id), customAttributes));
8624
8772
  return scimJson(listResponse(resources), SCIM_OK);
8625
8773
  }, { query: t26.Object({ filter: t26.Optional(t26.String()) }) }).get(userRoute, async ({ headers, params: { id }, request }) => {
8626
8774
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
@@ -8630,12 +8778,12 @@ var scimRoutes = ({
8630
8778
  if (user === undefined) {
8631
8779
  return scimError(SCIM_NOT_FOUND, "User not found");
8632
8780
  }
8633
- return scimJson(toUserResource(user, userLocation(request.url, id)), SCIM_OK);
8781
+ return scimJson(toUserResource(user, userLocation(request.url, id), customAttributes), SCIM_OK);
8634
8782
  }, { params: t26.Object({ id: t26.String() }) }).put(userRoute, async ({ body, headers, params: { id }, request }) => {
8635
8783
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8636
8784
  if (organizationId === undefined)
8637
8785
  return unauthorized();
8638
- const input = parseUserInput(body);
8786
+ const input = parseUserInput(body, customAttributes);
8639
8787
  if (input === undefined) {
8640
8788
  return scimError(SCIM_BAD_REQUEST, "Request body is not a valid SCIM User", "invalidValue");
8641
8789
  }
@@ -8647,7 +8795,7 @@ var scimRoutes = ({
8647
8795
  if (user === undefined) {
8648
8796
  return scimError(SCIM_NOT_FOUND, "User not found");
8649
8797
  }
8650
- return scimJson(toUserResource(user, userLocation(request.url, id)), SCIM_OK);
8798
+ return scimJson(toUserResource(user, userLocation(request.url, id), customAttributes), SCIM_OK);
8651
8799
  }, { params: t26.Object({ id: t26.String() }) }).patch(userRoute, async ({ body, headers, params: { id }, request }) => {
8652
8800
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8653
8801
  if (organizationId === undefined)
@@ -8664,7 +8812,7 @@ var scimRoutes = ({
8664
8812
  if (user === undefined) {
8665
8813
  return scimError(SCIM_NOT_FOUND, "User not found");
8666
8814
  }
8667
- return scimJson(toUserResource(user, userLocation(request.url, id)), SCIM_OK);
8815
+ return scimJson(toUserResource(user, userLocation(request.url, id), customAttributes), SCIM_OK);
8668
8816
  }, { params: t26.Object({ id: t26.String() }) }).delete(userRoute, async ({ headers, params: { id } }) => {
8669
8817
  const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8670
8818
  if (organizationId === undefined)
@@ -8756,6 +8904,34 @@ var scimRoutes = ({
8756
8904
  return notImplemented();
8757
8905
  await onScimGroupDelete({ id, organizationId });
8758
8906
  return new Response(null, { status: SCIM_NO_CONTENT });
8907
+ }, { params: t26.Object({ id: t26.String() }) }).get(schemasRoute, async ({ headers, request }) => {
8908
+ const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8909
+ if (organizationId === undefined)
8910
+ return unauthorized();
8911
+ return scimJson(schemaList(schemasLocation(request.url), extensionSchemas), SCIM_OK);
8912
+ }).get(schemaRoute, async ({ headers, params: { id }, request }) => {
8913
+ const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8914
+ if (organizationId === undefined)
8915
+ return unauthorized();
8916
+ const schema = schemaOne(`${schemasLocation(request.url)}/${id}`, id, extensionSchemas);
8917
+ if (schema === undefined) {
8918
+ return scimError(SCIM_NOT_FOUND, "Schema not found");
8919
+ }
8920
+ return scimJson(schema, SCIM_OK);
8921
+ }, { params: t26.Object({ id: t26.String() }) }).get(resourceTypesRoute, async ({ headers, request }) => {
8922
+ const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8923
+ if (organizationId === undefined)
8924
+ return unauthorized();
8925
+ return scimJson(resourceTypeList(resourceTypesLocation(request.url), usersEndpoint, groupsEndpoint, extensionSchemas), SCIM_OK);
8926
+ }).get(resourceTypeRoute, async ({ headers, params: { id }, request }) => {
8927
+ const organizationId = await resolveScimOrganization(scimTokenStore, headers.authorization);
8928
+ if (organizationId === undefined)
8929
+ return unauthorized();
8930
+ const resourceType = resourceTypeOne(`${resourceTypesLocation(request.url)}/${id}`, id, usersEndpoint, groupsEndpoint, extensionSchemas);
8931
+ if (resourceType === undefined) {
8932
+ return scimError(SCIM_NOT_FOUND, "ResourceType not found");
8933
+ }
8934
+ return scimJson(resourceType, SCIM_OK);
8759
8935
  }, { params: t26.Object({ id: t26.String() }) });
8760
8936
  };
8761
8937
 
@@ -21715,6 +21891,15 @@ var createPostgresAuditSink = (db) => ({
21715
21891
  return deleted.length;
21716
21892
  }
21717
21893
  });
21894
+ // src/scim/extensions.ts
21895
+ var defineScimAttributeMap = (map) => map;
21896
+ var diffScimGroupMembers = (current, next) => {
21897
+ const currentValues = new Set(current.map((member) => member.value));
21898
+ const nextValues = new Set(next.map((member) => member.value));
21899
+ const added = next.filter((member) => !currentValues.has(member.value));
21900
+ const removed = current.filter((member) => !nextValues.has(member.value));
21901
+ return { added, removed };
21902
+ };
21718
21903
  // src/scim/inMemoryScimTokenStore.ts
21719
21904
  var createInMemoryScimTokenStore = () => {
21720
21905
  const tokens = new Map;
@@ -24641,10 +24826,12 @@ export {
24641
24826
  endImpersonation,
24642
24827
  encryptTotpSecret,
24643
24828
  encryptSecret,
24829
+ diffScimGroupMembers,
24644
24830
  denyDeviceAuthorization,
24645
24831
  denyBackchannelAuth,
24646
24832
  deleteWarrant,
24647
24833
  deleteRegisteredClient,
24834
+ defineScimAttributeMap,
24648
24835
  defineProvidersConfiguration,
24649
24836
  defineAuthSettings,
24650
24837
  defineAuthHtmxConfig,
@@ -24846,5 +25033,5 @@ export {
24846
25033
  AuthIdentityConflictError
24847
25034
  };
24848
25035
 
24849
- //# debugId=26C38ACE51F8A69A64756E2164756E21
25036
+ //# debugId=5A0B79F67182545764756E2164756E21
24850
25037
  //# sourceMappingURL=index.js.map