@twin.org/api-auth-entity-storage-service 0.0.1 → 0.0.2-next.1

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.
@@ -388,7 +388,41 @@ function generateRestRoutesAuthentication(baseRouteName, componentName) {
388
388
  }
389
389
  ]
390
390
  };
391
- return [loginRoute, logoutRoute, refreshTokenRoute];
391
+ const updatePasswordRoute = {
392
+ operationId: "authenticationUpdatePassword",
393
+ summary: "Update the user's password",
394
+ tag: tagsAuthentication[0].name,
395
+ method: "PUT",
396
+ path: `${baseRouteName}/:email/password`,
397
+ handler: async (httpRequestContext, request) => authenticationUpdatePassword(httpRequestContext, componentName, request),
398
+ requestType: {
399
+ type: "IUpdatePasswordRequest",
400
+ examples: [
401
+ {
402
+ id: "updatePasswordRequestExample",
403
+ description: "The request to update the user's password.",
404
+ request: {
405
+ pathParams: {
406
+ email: "john:example.com"
407
+ },
408
+ body: {
409
+ currentPassword: "MyNewPassword123!",
410
+ newPassword: "MyNewPassword123!"
411
+ }
412
+ }
413
+ }
414
+ ]
415
+ },
416
+ responseType: [
417
+ {
418
+ type: "INoContentResponse"
419
+ },
420
+ {
421
+ type: "IUnauthorizedResponse"
422
+ }
423
+ ]
424
+ };
425
+ return [loginRoute, logoutRoute, refreshTokenRoute, updatePasswordRoute];
392
426
  }
393
427
  /**
394
428
  * Login to the server.
@@ -448,6 +482,23 @@ async function authenticationRefreshToken(httpRequestContext, componentName, req
448
482
  body: result
449
483
  };
450
484
  }
485
+ /**
486
+ * Update the user's password.
487
+ * @param httpRequestContext The request context for the API.
488
+ * @param componentName The name of the component to use in the routes.
489
+ * @param request The request.
490
+ * @returns The response object with additional http response properties.
491
+ */
492
+ async function authenticationUpdatePassword(httpRequestContext, componentName, request) {
493
+ core.Guards.object(ROUTES_SOURCE, "request", request);
494
+ core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
495
+ core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
496
+ const component = core.ComponentFactory.get(componentName);
497
+ await component.updatePassword(request.pathParams.email, request.body.currentPassword, request.body.newPassword);
498
+ return {
499
+ statusCode: web.HttpStatusCode.noContent
500
+ };
501
+ }
451
502
 
452
503
  const restEntryPoints = [
453
504
  {
@@ -495,6 +546,141 @@ class PasswordHelper {
495
546
  }
496
547
  }
497
548
 
549
+ /**
550
+ * Implementation of the authentication component using entity storage.
551
+ */
552
+ class EntityStorageAuthenticationAdminService {
553
+ /**
554
+ * The namespace supported by the authentication service.
555
+ */
556
+ static NAMESPACE = "authentication-admin-entity-storage";
557
+ /**
558
+ * The minimum password length.
559
+ * @internal
560
+ */
561
+ static _DEFAULT_MIN_PASSWORD_LENGTH = 8;
562
+ /**
563
+ * Runtime name for the class.
564
+ */
565
+ CLASS_NAME = "EntityStorageAuthenticationAdminService";
566
+ /**
567
+ * The entity storage for users.
568
+ * @internal
569
+ */
570
+ _userEntityStorage;
571
+ /**
572
+ * The minimum password length.
573
+ * @internal
574
+ */
575
+ _minPasswordLength;
576
+ /**
577
+ * Create a new instance of EntityStorageAuthentication.
578
+ * @param options The dependencies for the identity connector.
579
+ */
580
+ constructor(options) {
581
+ this._userEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.userEntityStorageType ?? "authentication-user");
582
+ this._minPasswordLength =
583
+ options?.config?.minPasswordLength ??
584
+ EntityStorageAuthenticationAdminService._DEFAULT_MIN_PASSWORD_LENGTH;
585
+ }
586
+ /**
587
+ * Create a login for the user.
588
+ * @param email The email address for the user.
589
+ * @param password The password for the user.
590
+ * @param identity The DID to associate with the account.
591
+ * @returns Nothing.
592
+ */
593
+ async create(email, password, identity) {
594
+ core.Guards.stringValue(this.CLASS_NAME, "email", email);
595
+ core.Guards.stringValue(this.CLASS_NAME, "password", password);
596
+ try {
597
+ if (password.length < this._minPasswordLength) {
598
+ throw new core.GeneralError(this.CLASS_NAME, "passwordTooShort", {
599
+ minLength: this._minPasswordLength
600
+ });
601
+ }
602
+ const user = await this._userEntityStorage.get(email);
603
+ if (user) {
604
+ throw new core.GeneralError(this.CLASS_NAME, "userExists");
605
+ }
606
+ const saltBytes = core.RandomHelper.generate(16);
607
+ const passwordBytes = core.Converter.utf8ToBytes(password);
608
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
609
+ const newUser = {
610
+ email,
611
+ salt: core.Converter.bytesToBase64(saltBytes),
612
+ password: hashedPassword,
613
+ identity
614
+ };
615
+ await this._userEntityStorage.set(newUser);
616
+ }
617
+ catch (error) {
618
+ throw new core.GeneralError(this.CLASS_NAME, "createUserFailed", undefined, error);
619
+ }
620
+ }
621
+ /**
622
+ * Remove the current user.
623
+ * @param email The email address of the user to remove.
624
+ * @returns Nothing.
625
+ */
626
+ async remove(email) {
627
+ core.Guards.stringValue(this.CLASS_NAME, "email", email);
628
+ try {
629
+ const user = await this._userEntityStorage.get(email);
630
+ if (!user) {
631
+ throw new core.NotFoundError(this.CLASS_NAME, "userNotFound", email);
632
+ }
633
+ await this._userEntityStorage.remove(email);
634
+ }
635
+ catch (error) {
636
+ throw new core.GeneralError(this.CLASS_NAME, "removeUserFailed", undefined, error);
637
+ }
638
+ }
639
+ /**
640
+ * Update the user's password.
641
+ * @param email The email address of the user to update.
642
+ * @param newPassword The new password for the user.
643
+ * @param currentPassword The current password, optional, if supplied will check against existing.
644
+ * @returns Nothing.
645
+ */
646
+ async updatePassword(email, newPassword, currentPassword) {
647
+ core.Guards.stringValue(this.CLASS_NAME, "email", email);
648
+ core.Guards.stringValue(this.CLASS_NAME, "newPassword", newPassword);
649
+ try {
650
+ if (newPassword.length < this._minPasswordLength) {
651
+ throw new core.GeneralError(this.CLASS_NAME, "passwordTooShort", {
652
+ minLength: this._minPasswordLength
653
+ });
654
+ }
655
+ const user = await this._userEntityStorage.get(email);
656
+ if (!user) {
657
+ throw new core.NotFoundError(this.CLASS_NAME, "userNotFound", email);
658
+ }
659
+ if (core.Is.stringValue(currentPassword)) {
660
+ const saltBytes = core.Converter.base64ToBytes(user.salt);
661
+ const passwordBytes = core.Converter.utf8ToBytes(currentPassword);
662
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
663
+ if (hashedPassword !== user.password) {
664
+ throw new core.GeneralError(this.CLASS_NAME, "currentPasswordMismatch");
665
+ }
666
+ }
667
+ const saltBytes = core.RandomHelper.generate(16);
668
+ const passwordBytes = core.Converter.utf8ToBytes(newPassword);
669
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
670
+ const updatedUser = {
671
+ email,
672
+ salt: core.Converter.bytesToBase64(saltBytes),
673
+ password: hashedPassword,
674
+ identity: user.identity
675
+ };
676
+ await this._userEntityStorage.set(updatedUser);
677
+ }
678
+ catch (error) {
679
+ throw new core.GeneralError(this.CLASS_NAME, "updatePasswordFailed", undefined, error);
680
+ }
681
+ }
682
+ }
683
+
498
684
  /**
499
685
  * Implementation of the authentication component using entity storage.
500
686
  */
@@ -512,6 +698,11 @@ class EntityStorageAuthenticationService {
512
698
  * Runtime name for the class.
513
699
  */
514
700
  CLASS_NAME = "EntityStorageAuthenticationService";
701
+ /**
702
+ * The user admin service.
703
+ * @internal
704
+ */
705
+ _authenticationAdminService;
515
706
  /**
516
707
  * The entity storage for users.
517
708
  * @internal
@@ -544,6 +735,7 @@ class EntityStorageAuthenticationService {
544
735
  constructor(options) {
545
736
  this._userEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.userEntityStorageType ?? "authentication-user");
546
737
  this._vaultConnector = vaultModels.VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
738
+ this._authenticationAdminService = core.ComponentFactory.get(options?.authenticationAdminServiceType ?? "authentication-admin");
547
739
  this._signingKeyName = options?.config?.signingKeyName ?? "auth-signing";
548
740
  this._defaultTtlMinutes =
549
741
  options?.config?.defaultTtlMinutes ?? EntityStorageAuthenticationService._DEFAULT_TTL_MINUTES;
@@ -604,15 +796,27 @@ class EntityStorageAuthenticationService {
604
796
  const refreshTokenAndExpiry = await TokenHelper.createToken(this._vaultConnector, `${this._nodeIdentity}/${this._signingKeyName}`, headerAndPayload.payload.sub ?? "", this._defaultTtlMinutes);
605
797
  return refreshTokenAndExpiry;
606
798
  }
799
+ /**
800
+ * Update the user's password.
801
+ * @param email The email address of the user to update.
802
+ * @param currentPassword The current password for the user.
803
+ * @param newPassword The new password for the user.
804
+ * @returns Nothing.
805
+ */
806
+ async updatePassword(email, currentPassword, newPassword) {
807
+ return this._authenticationAdminService.updatePassword(email, newPassword, currentPassword);
808
+ }
607
809
  }
608
810
 
609
811
  exports.AuthHeaderProcessor = AuthHeaderProcessor;
812
+ exports.EntityStorageAuthenticationAdminService = EntityStorageAuthenticationAdminService;
610
813
  exports.EntityStorageAuthenticationService = EntityStorageAuthenticationService;
611
814
  exports.PasswordHelper = PasswordHelper;
612
815
  exports.TokenHelper = TokenHelper;
613
816
  exports.authenticationLogin = authenticationLogin;
614
817
  exports.authenticationLogout = authenticationLogout;
615
818
  exports.authenticationRefreshToken = authenticationRefreshToken;
819
+ exports.authenticationUpdatePassword = authenticationUpdatePassword;
616
820
  exports.generateRestRoutesAuthentication = generateRestRoutesAuthentication;
617
821
  exports.initSchema = initSchema;
618
822
  exports.restEntryPoints = restEntryPoints;
@@ -1,6 +1,6 @@
1
1
  import { property, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
2
2
  import { HttpErrorHelper } from '@twin.org/api-models';
3
- import { Is, UnauthorizedError, Guards, BaseError, ComponentFactory, Converter, GeneralError } from '@twin.org/core';
3
+ import { Is, UnauthorizedError, Guards, BaseError, ComponentFactory, Converter, GeneralError, RandomHelper, NotFoundError } from '@twin.org/core';
4
4
  import { VaultConnectorHelper, VaultConnectorFactory } from '@twin.org/vault-models';
5
5
  import { Jwt, HeaderTypes, HttpStatusCode } from '@twin.org/web';
6
6
  import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
@@ -386,7 +386,41 @@ function generateRestRoutesAuthentication(baseRouteName, componentName) {
386
386
  }
387
387
  ]
388
388
  };
389
- return [loginRoute, logoutRoute, refreshTokenRoute];
389
+ const updatePasswordRoute = {
390
+ operationId: "authenticationUpdatePassword",
391
+ summary: "Update the user's password",
392
+ tag: tagsAuthentication[0].name,
393
+ method: "PUT",
394
+ path: `${baseRouteName}/:email/password`,
395
+ handler: async (httpRequestContext, request) => authenticationUpdatePassword(httpRequestContext, componentName, request),
396
+ requestType: {
397
+ type: "IUpdatePasswordRequest",
398
+ examples: [
399
+ {
400
+ id: "updatePasswordRequestExample",
401
+ description: "The request to update the user's password.",
402
+ request: {
403
+ pathParams: {
404
+ email: "john:example.com"
405
+ },
406
+ body: {
407
+ currentPassword: "MyNewPassword123!",
408
+ newPassword: "MyNewPassword123!"
409
+ }
410
+ }
411
+ }
412
+ ]
413
+ },
414
+ responseType: [
415
+ {
416
+ type: "INoContentResponse"
417
+ },
418
+ {
419
+ type: "IUnauthorizedResponse"
420
+ }
421
+ ]
422
+ };
423
+ return [loginRoute, logoutRoute, refreshTokenRoute, updatePasswordRoute];
390
424
  }
391
425
  /**
392
426
  * Login to the server.
@@ -446,6 +480,23 @@ async function authenticationRefreshToken(httpRequestContext, componentName, req
446
480
  body: result
447
481
  };
448
482
  }
483
+ /**
484
+ * Update the user's password.
485
+ * @param httpRequestContext The request context for the API.
486
+ * @param componentName The name of the component to use in the routes.
487
+ * @param request The request.
488
+ * @returns The response object with additional http response properties.
489
+ */
490
+ async function authenticationUpdatePassword(httpRequestContext, componentName, request) {
491
+ Guards.object(ROUTES_SOURCE, "request", request);
492
+ Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
493
+ Guards.object(ROUTES_SOURCE, "request.body", request.body);
494
+ const component = ComponentFactory.get(componentName);
495
+ await component.updatePassword(request.pathParams.email, request.body.currentPassword, request.body.newPassword);
496
+ return {
497
+ statusCode: HttpStatusCode.noContent
498
+ };
499
+ }
449
500
 
450
501
  const restEntryPoints = [
451
502
  {
@@ -493,6 +544,141 @@ class PasswordHelper {
493
544
  }
494
545
  }
495
546
 
547
+ /**
548
+ * Implementation of the authentication component using entity storage.
549
+ */
550
+ class EntityStorageAuthenticationAdminService {
551
+ /**
552
+ * The namespace supported by the authentication service.
553
+ */
554
+ static NAMESPACE = "authentication-admin-entity-storage";
555
+ /**
556
+ * The minimum password length.
557
+ * @internal
558
+ */
559
+ static _DEFAULT_MIN_PASSWORD_LENGTH = 8;
560
+ /**
561
+ * Runtime name for the class.
562
+ */
563
+ CLASS_NAME = "EntityStorageAuthenticationAdminService";
564
+ /**
565
+ * The entity storage for users.
566
+ * @internal
567
+ */
568
+ _userEntityStorage;
569
+ /**
570
+ * The minimum password length.
571
+ * @internal
572
+ */
573
+ _minPasswordLength;
574
+ /**
575
+ * Create a new instance of EntityStorageAuthentication.
576
+ * @param options The dependencies for the identity connector.
577
+ */
578
+ constructor(options) {
579
+ this._userEntityStorage = EntityStorageConnectorFactory.get(options?.userEntityStorageType ?? "authentication-user");
580
+ this._minPasswordLength =
581
+ options?.config?.minPasswordLength ??
582
+ EntityStorageAuthenticationAdminService._DEFAULT_MIN_PASSWORD_LENGTH;
583
+ }
584
+ /**
585
+ * Create a login for the user.
586
+ * @param email The email address for the user.
587
+ * @param password The password for the user.
588
+ * @param identity The DID to associate with the account.
589
+ * @returns Nothing.
590
+ */
591
+ async create(email, password, identity) {
592
+ Guards.stringValue(this.CLASS_NAME, "email", email);
593
+ Guards.stringValue(this.CLASS_NAME, "password", password);
594
+ try {
595
+ if (password.length < this._minPasswordLength) {
596
+ throw new GeneralError(this.CLASS_NAME, "passwordTooShort", {
597
+ minLength: this._minPasswordLength
598
+ });
599
+ }
600
+ const user = await this._userEntityStorage.get(email);
601
+ if (user) {
602
+ throw new GeneralError(this.CLASS_NAME, "userExists");
603
+ }
604
+ const saltBytes = RandomHelper.generate(16);
605
+ const passwordBytes = Converter.utf8ToBytes(password);
606
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
607
+ const newUser = {
608
+ email,
609
+ salt: Converter.bytesToBase64(saltBytes),
610
+ password: hashedPassword,
611
+ identity
612
+ };
613
+ await this._userEntityStorage.set(newUser);
614
+ }
615
+ catch (error) {
616
+ throw new GeneralError(this.CLASS_NAME, "createUserFailed", undefined, error);
617
+ }
618
+ }
619
+ /**
620
+ * Remove the current user.
621
+ * @param email The email address of the user to remove.
622
+ * @returns Nothing.
623
+ */
624
+ async remove(email) {
625
+ Guards.stringValue(this.CLASS_NAME, "email", email);
626
+ try {
627
+ const user = await this._userEntityStorage.get(email);
628
+ if (!user) {
629
+ throw new NotFoundError(this.CLASS_NAME, "userNotFound", email);
630
+ }
631
+ await this._userEntityStorage.remove(email);
632
+ }
633
+ catch (error) {
634
+ throw new GeneralError(this.CLASS_NAME, "removeUserFailed", undefined, error);
635
+ }
636
+ }
637
+ /**
638
+ * Update the user's password.
639
+ * @param email The email address of the user to update.
640
+ * @param newPassword The new password for the user.
641
+ * @param currentPassword The current password, optional, if supplied will check against existing.
642
+ * @returns Nothing.
643
+ */
644
+ async updatePassword(email, newPassword, currentPassword) {
645
+ Guards.stringValue(this.CLASS_NAME, "email", email);
646
+ Guards.stringValue(this.CLASS_NAME, "newPassword", newPassword);
647
+ try {
648
+ if (newPassword.length < this._minPasswordLength) {
649
+ throw new GeneralError(this.CLASS_NAME, "passwordTooShort", {
650
+ minLength: this._minPasswordLength
651
+ });
652
+ }
653
+ const user = await this._userEntityStorage.get(email);
654
+ if (!user) {
655
+ throw new NotFoundError(this.CLASS_NAME, "userNotFound", email);
656
+ }
657
+ if (Is.stringValue(currentPassword)) {
658
+ const saltBytes = Converter.base64ToBytes(user.salt);
659
+ const passwordBytes = Converter.utf8ToBytes(currentPassword);
660
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
661
+ if (hashedPassword !== user.password) {
662
+ throw new GeneralError(this.CLASS_NAME, "currentPasswordMismatch");
663
+ }
664
+ }
665
+ const saltBytes = RandomHelper.generate(16);
666
+ const passwordBytes = Converter.utf8ToBytes(newPassword);
667
+ const hashedPassword = await PasswordHelper.hashPassword(passwordBytes, saltBytes);
668
+ const updatedUser = {
669
+ email,
670
+ salt: Converter.bytesToBase64(saltBytes),
671
+ password: hashedPassword,
672
+ identity: user.identity
673
+ };
674
+ await this._userEntityStorage.set(updatedUser);
675
+ }
676
+ catch (error) {
677
+ throw new GeneralError(this.CLASS_NAME, "updatePasswordFailed", undefined, error);
678
+ }
679
+ }
680
+ }
681
+
496
682
  /**
497
683
  * Implementation of the authentication component using entity storage.
498
684
  */
@@ -510,6 +696,11 @@ class EntityStorageAuthenticationService {
510
696
  * Runtime name for the class.
511
697
  */
512
698
  CLASS_NAME = "EntityStorageAuthenticationService";
699
+ /**
700
+ * The user admin service.
701
+ * @internal
702
+ */
703
+ _authenticationAdminService;
513
704
  /**
514
705
  * The entity storage for users.
515
706
  * @internal
@@ -542,6 +733,7 @@ class EntityStorageAuthenticationService {
542
733
  constructor(options) {
543
734
  this._userEntityStorage = EntityStorageConnectorFactory.get(options?.userEntityStorageType ?? "authentication-user");
544
735
  this._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
736
+ this._authenticationAdminService = ComponentFactory.get(options?.authenticationAdminServiceType ?? "authentication-admin");
545
737
  this._signingKeyName = options?.config?.signingKeyName ?? "auth-signing";
546
738
  this._defaultTtlMinutes =
547
739
  options?.config?.defaultTtlMinutes ?? EntityStorageAuthenticationService._DEFAULT_TTL_MINUTES;
@@ -602,6 +794,16 @@ class EntityStorageAuthenticationService {
602
794
  const refreshTokenAndExpiry = await TokenHelper.createToken(this._vaultConnector, `${this._nodeIdentity}/${this._signingKeyName}`, headerAndPayload.payload.sub ?? "", this._defaultTtlMinutes);
603
795
  return refreshTokenAndExpiry;
604
796
  }
797
+ /**
798
+ * Update the user's password.
799
+ * @param email The email address of the user to update.
800
+ * @param currentPassword The current password for the user.
801
+ * @param newPassword The new password for the user.
802
+ * @returns Nothing.
803
+ */
804
+ async updatePassword(email, currentPassword, newPassword) {
805
+ return this._authenticationAdminService.updatePassword(email, newPassword, currentPassword);
806
+ }
605
807
  }
606
808
 
607
- export { AuthHeaderProcessor, AuthenticationUser, EntityStorageAuthenticationService, PasswordHelper, TokenHelper, authenticationLogin, authenticationLogout, authenticationRefreshToken, generateRestRoutesAuthentication, initSchema, restEntryPoints, tagsAuthentication };
809
+ export { AuthHeaderProcessor, AuthenticationUser, EntityStorageAuthenticationAdminService, EntityStorageAuthenticationService, PasswordHelper, TokenHelper, authenticationLogin, authenticationLogout, authenticationRefreshToken, authenticationUpdatePassword, generateRestRoutesAuthentication, initSchema, restEntryPoints, tagsAuthentication };
@@ -1,12 +1,15 @@
1
1
  export * from "./entities/authenticationUser";
2
2
  export * from "./models/IAuthHeaderProcessorConfig";
3
3
  export * from "./models/IAuthHeaderProcessorConstructorOptions";
4
+ export * from "./models/IEntityStorageAuthenticationAdminServiceConfig";
5
+ export * from "./models/IEntityStorageAuthenticationAdminServiceConstructorOptions";
4
6
  export * from "./models/IEntityStorageAuthenticationServiceConfig";
5
7
  export * from "./models/IEntityStorageAuthenticationServiceConstructorOptions";
6
8
  export * from "./processors/authHeaderProcessor";
7
9
  export * from "./restEntryPoints";
8
10
  export * from "./routes/entityStorageAuthenticationRoutes";
9
11
  export * from "./schema";
12
+ export * from "./services/entityStorageAuthenticationAdminService";
10
13
  export * from "./services/entityStorageAuthenticationService";
11
14
  export * from "./utils/passwordHelper";
12
15
  export * from "./utils/tokenHelper";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Configuration for the entity storage authentication admin service.
3
+ */
4
+ export interface IEntityStorageAuthenticationAdminServiceConfig {
5
+ /**
6
+ * The minimum password length.
7
+ * @default 8
8
+ */
9
+ minPasswordLength?: number;
10
+ }
@@ -0,0 +1,15 @@
1
+ import type { IEntityStorageAuthenticationAdminServiceConfig } from "./IEntityStorageAuthenticationAdminServiceConfig";
2
+ /**
3
+ * Options for the EntityStorageAuthenticationAdminService constructor.
4
+ */
5
+ export interface IEntityStorageAuthenticationAdminServiceConstructorOptions {
6
+ /**
7
+ * The entity storage for the users.
8
+ * @default authentication-user
9
+ */
10
+ userEntityStorageType?: string;
11
+ /**
12
+ * The configuration for the authentication.
13
+ */
14
+ config?: IEntityStorageAuthenticationAdminServiceConfig;
15
+ }
@@ -13,6 +13,11 @@ export interface IEntityStorageAuthenticationServiceConstructorOptions {
13
13
  * @default vault
14
14
  */
15
15
  vaultConnectorType?: string;
16
+ /**
17
+ * The admin service.
18
+ * @default authentication-admin
19
+ */
20
+ authenticationAdminServiceType?: string;
16
21
  /**
17
22
  * The configuration for the authentication.
18
23
  */
@@ -1,4 +1,4 @@
1
- import type { ILoginRequest, ILoginResponse, ILogoutRequest, IRefreshTokenRequest, IRefreshTokenResponse } from "@twin.org/api-auth-entity-storage-models";
1
+ import type { ILoginRequest, ILoginResponse, ILogoutRequest, IRefreshTokenRequest, IRefreshTokenResponse, IUpdatePasswordRequest } from "@twin.org/api-auth-entity-storage-models";
2
2
  import type { IHttpRequestContext, INoContentResponse, IRestRoute, IRestRouteResponseOptions, ITag } from "@twin.org/api-models";
3
3
  /**
4
4
  * The tag to associate with the routes.
@@ -35,3 +35,11 @@ export declare function authenticationLogout(httpRequestContext: IHttpRequestCon
35
35
  * @returns The response object with additional http response properties.
36
36
  */
37
37
  export declare function authenticationRefreshToken(httpRequestContext: IHttpRequestContext, componentName: string, request: IRefreshTokenRequest): Promise<IRefreshTokenResponse & IRestRouteResponseOptions>;
38
+ /**
39
+ * Update the user's password.
40
+ * @param httpRequestContext The request context for the API.
41
+ * @param componentName The name of the component to use in the routes.
42
+ * @param request The request.
43
+ * @returns The response object with additional http response properties.
44
+ */
45
+ export declare function authenticationUpdatePassword(httpRequestContext: IHttpRequestContext, componentName: string, request: IUpdatePasswordRequest): Promise<INoContentResponse>;
@@ -0,0 +1,42 @@
1
+ import type { IAuthenticationAdminComponent } from "@twin.org/api-auth-entity-storage-models";
2
+ import type { IEntityStorageAuthenticationAdminServiceConstructorOptions } from "../models/IEntityStorageAuthenticationAdminServiceConstructorOptions";
3
+ /**
4
+ * Implementation of the authentication component using entity storage.
5
+ */
6
+ export declare class EntityStorageAuthenticationAdminService implements IAuthenticationAdminComponent {
7
+ /**
8
+ * The namespace supported by the authentication service.
9
+ */
10
+ static readonly NAMESPACE: string;
11
+ /**
12
+ * Runtime name for the class.
13
+ */
14
+ readonly CLASS_NAME: string;
15
+ /**
16
+ * Create a new instance of EntityStorageAuthentication.
17
+ * @param options The dependencies for the identity connector.
18
+ */
19
+ constructor(options?: IEntityStorageAuthenticationAdminServiceConstructorOptions);
20
+ /**
21
+ * Create a login for the user.
22
+ * @param email The email address for the user.
23
+ * @param password The password for the user.
24
+ * @param identity The DID to associate with the account.
25
+ * @returns Nothing.
26
+ */
27
+ create(email: string, password: string, identity: string): Promise<void>;
28
+ /**
29
+ * Remove the current user.
30
+ * @param email The email address of the user to remove.
31
+ * @returns Nothing.
32
+ */
33
+ remove(email: string): Promise<void>;
34
+ /**
35
+ * Update the user's password.
36
+ * @param email The email address of the user to update.
37
+ * @param newPassword The new password for the user.
38
+ * @param currentPassword The current password, optional, if supplied will check against existing.
39
+ * @returns Nothing.
40
+ */
41
+ updatePassword(email: string, newPassword: string, currentPassword?: string): Promise<void>;
42
+ }
@@ -49,4 +49,12 @@ export declare class EntityStorageAuthenticationService implements IAuthenticati
49
49
  token: string;
50
50
  expiry: number;
51
51
  }>;
52
+ /**
53
+ * Update the user's password.
54
+ * @param email The email address of the user to update.
55
+ * @param currentPassword The current password for the user.
56
+ * @param newPassword The new password for the user.
57
+ * @returns Nothing.
58
+ */
59
+ updatePassword(email: string, currentPassword: string, newPassword: string): Promise<void>;
52
60
  }
package/docs/changelog.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @twin.org/api-auth-entity-storage-service - Changelog
2
2
 
3
+ ## [0.0.2-next.1](https://github.com/twinfoundation/api/compare/api-auth-entity-storage-service-v0.0.2-next.0...api-auth-entity-storage-service-v0.0.2-next.1) (2025-07-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * add json-ld mime type processor and auth admin component ([8861791](https://github.com/twinfoundation/api/commit/88617916e23bfbca023dbae1976fe421983a02ff))
9
+ * update dependencies ([1171dc4](https://github.com/twinfoundation/api/commit/1171dc416a9481737f6a640e3cf30145768f37e9))
10
+ * use shared store mechanism ([#19](https://github.com/twinfoundation/api/issues/19)) ([32116df](https://github.com/twinfoundation/api/commit/32116df3b4380a30137f5056f242a5c99afa2df9))
11
+
12
+
13
+ ### Dependencies
14
+
15
+ * The following workspace dependencies were updated
16
+ * dependencies
17
+ * @twin.org/api-auth-entity-storage-models bumped from 0.0.2-next.0 to 0.0.2-next.1
18
+ * @twin.org/api-core bumped from 0.0.2-next.0 to 0.0.2-next.1
19
+ * @twin.org/api-models bumped from 0.0.2-next.0 to 0.0.2-next.1
20
+
3
21
  ## 0.0.1 (2025-07-03)
4
22
 
5
23
 
@@ -0,0 +1,149 @@
1
+ # Class: EntityStorageAuthenticationAdminService
2
+
3
+ Implementation of the authentication component using entity storage.
4
+
5
+ ## Implements
6
+
7
+ - `IAuthenticationAdminComponent`
8
+
9
+ ## Constructors
10
+
11
+ ### Constructor
12
+
13
+ > **new EntityStorageAuthenticationAdminService**(`options?`): `EntityStorageAuthenticationAdminService`
14
+
15
+ Create a new instance of EntityStorageAuthentication.
16
+
17
+ #### Parameters
18
+
19
+ ##### options?
20
+
21
+ [`IEntityStorageAuthenticationAdminServiceConstructorOptions`](../interfaces/IEntityStorageAuthenticationAdminServiceConstructorOptions.md)
22
+
23
+ The dependencies for the identity connector.
24
+
25
+ #### Returns
26
+
27
+ `EntityStorageAuthenticationAdminService`
28
+
29
+ ## Properties
30
+
31
+ ### NAMESPACE
32
+
33
+ > `readonly` `static` **NAMESPACE**: `string` = `"authentication-admin-entity-storage"`
34
+
35
+ The namespace supported by the authentication service.
36
+
37
+ ***
38
+
39
+ ### CLASS\_NAME
40
+
41
+ > `readonly` **CLASS\_NAME**: `string`
42
+
43
+ Runtime name for the class.
44
+
45
+ #### Implementation of
46
+
47
+ `IAuthenticationAdminComponent.CLASS_NAME`
48
+
49
+ ## Methods
50
+
51
+ ### create()
52
+
53
+ > **create**(`email`, `password`, `identity`): `Promise`\<`void`\>
54
+
55
+ Create a login for the user.
56
+
57
+ #### Parameters
58
+
59
+ ##### email
60
+
61
+ `string`
62
+
63
+ The email address for the user.
64
+
65
+ ##### password
66
+
67
+ `string`
68
+
69
+ The password for the user.
70
+
71
+ ##### identity
72
+
73
+ `string`
74
+
75
+ The DID to associate with the account.
76
+
77
+ #### Returns
78
+
79
+ `Promise`\<`void`\>
80
+
81
+ Nothing.
82
+
83
+ #### Implementation of
84
+
85
+ `IAuthenticationAdminComponent.create`
86
+
87
+ ***
88
+
89
+ ### remove()
90
+
91
+ > **remove**(`email`): `Promise`\<`void`\>
92
+
93
+ Remove the current user.
94
+
95
+ #### Parameters
96
+
97
+ ##### email
98
+
99
+ `string`
100
+
101
+ The email address of the user to remove.
102
+
103
+ #### Returns
104
+
105
+ `Promise`\<`void`\>
106
+
107
+ Nothing.
108
+
109
+ #### Implementation of
110
+
111
+ `IAuthenticationAdminComponent.remove`
112
+
113
+ ***
114
+
115
+ ### updatePassword()
116
+
117
+ > **updatePassword**(`email`, `newPassword`, `currentPassword?`): `Promise`\<`void`\>
118
+
119
+ Update the user's password.
120
+
121
+ #### Parameters
122
+
123
+ ##### email
124
+
125
+ `string`
126
+
127
+ The email address of the user to update.
128
+
129
+ ##### newPassword
130
+
131
+ `string`
132
+
133
+ The new password for the user.
134
+
135
+ ##### currentPassword?
136
+
137
+ `string`
138
+
139
+ The current password, optional, if supplied will check against existing.
140
+
141
+ #### Returns
142
+
143
+ `Promise`\<`void`\>
144
+
145
+ Nothing.
146
+
147
+ #### Implementation of
148
+
149
+ `IAuthenticationAdminComponent.updatePassword`
@@ -161,3 +161,41 @@ The refreshed token, if it uses a mechanism with public access.
161
161
  #### Implementation of
162
162
 
163
163
  `IAuthenticationComponent.refresh`
164
+
165
+ ***
166
+
167
+ ### updatePassword()
168
+
169
+ > **updatePassword**(`email`, `currentPassword`, `newPassword`): `Promise`\<`void`\>
170
+
171
+ Update the user's password.
172
+
173
+ #### Parameters
174
+
175
+ ##### email
176
+
177
+ `string`
178
+
179
+ The email address of the user to update.
180
+
181
+ ##### currentPassword
182
+
183
+ `string`
184
+
185
+ The current password for the user.
186
+
187
+ ##### newPassword
188
+
189
+ `string`
190
+
191
+ The new password for the user.
192
+
193
+ #### Returns
194
+
195
+ `Promise`\<`void`\>
196
+
197
+ Nothing.
198
+
199
+ #### Implementation of
200
+
201
+ `IAuthenticationComponent.updatePassword`
@@ -0,0 +1,31 @@
1
+ # Function: authenticationUpdatePassword()
2
+
3
+ > **authenticationUpdatePassword**(`httpRequestContext`, `componentName`, `request`): `Promise`\<`INoContentResponse`\>
4
+
5
+ Update the user's password.
6
+
7
+ ## Parameters
8
+
9
+ ### httpRequestContext
10
+
11
+ `IHttpRequestContext`
12
+
13
+ The request context for the API.
14
+
15
+ ### componentName
16
+
17
+ `string`
18
+
19
+ The name of the component to use in the routes.
20
+
21
+ ### request
22
+
23
+ `IUpdatePasswordRequest`
24
+
25
+ The request.
26
+
27
+ ## Returns
28
+
29
+ `Promise`\<`INoContentResponse`\>
30
+
31
+ The response object with additional http response properties.
@@ -4,6 +4,7 @@
4
4
 
5
5
  - [AuthenticationUser](classes/AuthenticationUser.md)
6
6
  - [AuthHeaderProcessor](classes/AuthHeaderProcessor.md)
7
+ - [EntityStorageAuthenticationAdminService](classes/EntityStorageAuthenticationAdminService.md)
7
8
  - [EntityStorageAuthenticationService](classes/EntityStorageAuthenticationService.md)
8
9
  - [PasswordHelper](classes/PasswordHelper.md)
9
10
  - [TokenHelper](classes/TokenHelper.md)
@@ -12,6 +13,8 @@
12
13
 
13
14
  - [IAuthHeaderProcessorConfig](interfaces/IAuthHeaderProcessorConfig.md)
14
15
  - [IAuthHeaderProcessorConstructorOptions](interfaces/IAuthHeaderProcessorConstructorOptions.md)
16
+ - [IEntityStorageAuthenticationAdminServiceConfig](interfaces/IEntityStorageAuthenticationAdminServiceConfig.md)
17
+ - [IEntityStorageAuthenticationAdminServiceConstructorOptions](interfaces/IEntityStorageAuthenticationAdminServiceConstructorOptions.md)
15
18
  - [IEntityStorageAuthenticationServiceConfig](interfaces/IEntityStorageAuthenticationServiceConfig.md)
16
19
  - [IEntityStorageAuthenticationServiceConstructorOptions](interfaces/IEntityStorageAuthenticationServiceConstructorOptions.md)
17
20
 
@@ -26,4 +29,5 @@
26
29
  - [authenticationLogin](functions/authenticationLogin.md)
27
30
  - [authenticationLogout](functions/authenticationLogout.md)
28
31
  - [authenticationRefreshToken](functions/authenticationRefreshToken.md)
32
+ - [authenticationUpdatePassword](functions/authenticationUpdatePassword.md)
29
33
  - [initSchema](functions/initSchema.md)
@@ -0,0 +1,17 @@
1
+ # Interface: IEntityStorageAuthenticationAdminServiceConfig
2
+
3
+ Configuration for the entity storage authentication admin service.
4
+
5
+ ## Properties
6
+
7
+ ### minPasswordLength?
8
+
9
+ > `optional` **minPasswordLength**: `number`
10
+
11
+ The minimum password length.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ 8
17
+ ```
@@ -0,0 +1,25 @@
1
+ # Interface: IEntityStorageAuthenticationAdminServiceConstructorOptions
2
+
3
+ Options for the EntityStorageAuthenticationAdminService constructor.
4
+
5
+ ## Properties
6
+
7
+ ### userEntityStorageType?
8
+
9
+ > `optional` **userEntityStorageType**: `string`
10
+
11
+ The entity storage for the users.
12
+
13
+ #### Default
14
+
15
+ ```ts
16
+ authentication-user
17
+ ```
18
+
19
+ ***
20
+
21
+ ### config?
22
+
23
+ > `optional` **config**: [`IEntityStorageAuthenticationAdminServiceConfig`](IEntityStorageAuthenticationAdminServiceConfig.md)
24
+
25
+ The configuration for the authentication.
@@ -32,6 +32,20 @@ vault
32
32
 
33
33
  ***
34
34
 
35
+ ### authenticationAdminServiceType?
36
+
37
+ > `optional` **authenticationAdminServiceType**: `string`
38
+
39
+ The admin service.
40
+
41
+ #### Default
42
+
43
+ ```ts
44
+ authentication-admin
45
+ ```
46
+
47
+ ***
48
+
35
49
  ### config?
36
50
 
37
51
  > `optional` **config**: [`IEntityStorageAuthenticationServiceConfig`](IEntityStorageAuthenticationServiceConfig.md)
package/locales/en.json CHANGED
@@ -6,6 +6,15 @@
6
6
  "userNotFound": "The user with the specified e-mail could not be found",
7
7
  "passwordMismatch": "The password does not match the user's password"
8
8
  },
9
+ "entityStorageAuthenticationAdminService": {
10
+ "userExists": "The user with the specified e-mail already exists",
11
+ "createFailed": "Creating the user failed",
12
+ "removeFailed": "Removing the user failed",
13
+ "updatePasswordFailed": "Updating the user's password failed",
14
+ "passwordTooShort": "The password is too short, it must be at least {minLength} characters long",
15
+ "userNotFound": "The user with the specified e-mail could not be found \"{notFoundId}\"",
16
+ "currentPasswordMismatch": "The current password is incorrect"
17
+ },
9
18
  "entityStorageAuthenticationProcessor": {
10
19
  "initializeFailed": "The JSON Web token authentication processor could not be initialized"
11
20
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/api-auth-entity-storage-service",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-next.1",
4
4
  "description": "Auth Entity Storage contract implementation and REST endpoint definitions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,17 +14,17 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/api-auth-entity-storage-models": "^0.0.1",
18
- "@twin.org/api-core": "^0.0.1",
19
- "@twin.org/api-models": "^0.0.1",
20
- "@twin.org/core": "^0.0.1",
21
- "@twin.org/crypto": "^0.0.1",
22
- "@twin.org/entity": "^0.0.1",
23
- "@twin.org/entity-storage-models": "^0.0.1-next.2",
24
- "@twin.org/logging-models": "^0.0.1-next.2",
25
- "@twin.org/nameof": "^0.0.1",
26
- "@twin.org/vault-models": "^0.0.1-next.2",
27
- "@twin.org/web": "^0.0.1"
17
+ "@twin.org/api-auth-entity-storage-models": "0.0.2-next.1",
18
+ "@twin.org/api-core": "0.0.2-next.1",
19
+ "@twin.org/api-models": "0.0.2-next.1",
20
+ "@twin.org/core": "next",
21
+ "@twin.org/crypto": "next",
22
+ "@twin.org/entity": "next",
23
+ "@twin.org/entity-storage-models": "next",
24
+ "@twin.org/logging-models": "next",
25
+ "@twin.org/nameof": "next",
26
+ "@twin.org/vault-models": "next",
27
+ "@twin.org/web": "next"
28
28
  },
29
29
  "main": "./dist/cjs/index.cjs",
30
30
  "module": "./dist/esm/index.mjs",