@twin.org/api-auth-entity-storage-service 0.0.2-next.9 → 0.0.3-next.10

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.
Files changed (53) hide show
  1. package/dist/es/entities/authenticationUser.js +53 -0
  2. package/dist/es/entities/authenticationUser.js.map +1 -0
  3. package/dist/es/index.js +18 -0
  4. package/dist/es/index.js.map +1 -0
  5. package/dist/es/models/IAuthHeaderProcessorConfig.js +4 -0
  6. package/dist/es/models/IAuthHeaderProcessorConfig.js.map +1 -0
  7. package/dist/es/models/IAuthHeaderProcessorConstructorOptions.js +2 -0
  8. package/dist/es/models/IAuthHeaderProcessorConstructorOptions.js.map +1 -0
  9. package/dist/es/models/IEntityStorageAuthenticationAdminServiceConfig.js +4 -0
  10. package/dist/es/models/IEntityStorageAuthenticationAdminServiceConfig.js.map +1 -0
  11. package/dist/es/models/IEntityStorageAuthenticationAdminServiceConstructorOptions.js +2 -0
  12. package/dist/es/models/IEntityStorageAuthenticationAdminServiceConstructorOptions.js.map +1 -0
  13. package/dist/es/models/IEntityStorageAuthenticationServiceConfig.js +4 -0
  14. package/dist/es/models/IEntityStorageAuthenticationServiceConfig.js.map +1 -0
  15. package/dist/es/models/IEntityStorageAuthenticationServiceConstructorOptions.js +2 -0
  16. package/dist/es/models/IEntityStorageAuthenticationServiceConstructorOptions.js.map +1 -0
  17. package/dist/es/processors/authHeaderProcessor.js +134 -0
  18. package/dist/es/processors/authHeaderProcessor.js.map +1 -0
  19. package/dist/es/restEntryPoints.js +10 -0
  20. package/dist/es/restEntryPoints.js.map +1 -0
  21. package/dist/es/routes/entityStorageAuthenticationRoutes.js +252 -0
  22. package/dist/es/routes/entityStorageAuthenticationRoutes.js.map +1 -0
  23. package/dist/es/schema.js +11 -0
  24. package/dist/es/schema.js.map +1 -0
  25. package/dist/es/services/entityStorageAuthenticationAdminService.js +146 -0
  26. package/dist/es/services/entityStorageAuthenticationAdminService.js.map +1 -0
  27. package/dist/es/services/entityStorageAuthenticationService.js +141 -0
  28. package/dist/es/services/entityStorageAuthenticationService.js.map +1 -0
  29. package/dist/es/utils/passwordHelper.js +29 -0
  30. package/dist/es/utils/passwordHelper.js.map +1 -0
  31. package/dist/es/utils/tokenHelper.js +94 -0
  32. package/dist/es/utils/tokenHelper.js.map +1 -0
  33. package/dist/types/entities/authenticationUser.d.ts +4 -0
  34. package/dist/types/index.d.ts +15 -15
  35. package/dist/types/models/IAuthHeaderProcessorConstructorOptions.d.ts +1 -1
  36. package/dist/types/models/IEntityStorageAuthenticationAdminServiceConstructorOptions.d.ts +1 -1
  37. package/dist/types/models/IEntityStorageAuthenticationServiceConstructorOptions.d.ts +1 -1
  38. package/dist/types/processors/authHeaderProcessor.d.ts +14 -9
  39. package/dist/types/services/entityStorageAuthenticationAdminService.d.ts +10 -4
  40. package/dist/types/services/entityStorageAuthenticationService.d.ts +9 -5
  41. package/dist/types/utils/passwordHelper.d.ts +4 -0
  42. package/dist/types/utils/tokenHelper.d.ts +8 -2
  43. package/docs/changelog.md +268 -0
  44. package/docs/reference/classes/AuthHeaderProcessor.md +28 -20
  45. package/docs/reference/classes/AuthenticationUser.md +8 -0
  46. package/docs/reference/classes/EntityStorageAuthenticationAdminService.md +25 -5
  47. package/docs/reference/classes/EntityStorageAuthenticationService.md +20 -12
  48. package/docs/reference/classes/PasswordHelper.md +8 -0
  49. package/docs/reference/classes/TokenHelper.md +27 -7
  50. package/locales/en.json +6 -6
  51. package/package.json +29 -11
  52. package/dist/cjs/index.cjs +0 -811
  53. package/dist/esm/index.mjs +0 -797
@@ -0,0 +1,53 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { entity, property } from "@twin.org/entity";
4
+ /**
5
+ * Class defining the storage for user login credentials.
6
+ */
7
+ let AuthenticationUser = class AuthenticationUser {
8
+ /**
9
+ * The user e-mail address.
10
+ */
11
+ email;
12
+ /**
13
+ * The encrypted password for the user.
14
+ */
15
+ password;
16
+ /**
17
+ * The salt for the password.
18
+ */
19
+ salt;
20
+ /**
21
+ * The user identity.
22
+ */
23
+ identity;
24
+ /**
25
+ * The users organization.
26
+ */
27
+ organization;
28
+ };
29
+ __decorate([
30
+ property({ type: "string", isPrimary: true }),
31
+ __metadata("design:type", String)
32
+ ], AuthenticationUser.prototype, "email", void 0);
33
+ __decorate([
34
+ property({ type: "string" }),
35
+ __metadata("design:type", String)
36
+ ], AuthenticationUser.prototype, "password", void 0);
37
+ __decorate([
38
+ property({ type: "string" }),
39
+ __metadata("design:type", String)
40
+ ], AuthenticationUser.prototype, "salt", void 0);
41
+ __decorate([
42
+ property({ type: "string" }),
43
+ __metadata("design:type", String)
44
+ ], AuthenticationUser.prototype, "identity", void 0);
45
+ __decorate([
46
+ property({ type: "string" }),
47
+ __metadata("design:type", String)
48
+ ], AuthenticationUser.prototype, "organization", void 0);
49
+ AuthenticationUser = __decorate([
50
+ entity()
51
+ ], AuthenticationUser);
52
+ export { AuthenticationUser };
53
+ //# sourceMappingURL=authenticationUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticationUser.js","sourceRoot":"","sources":["../../../src/entities/authenticationUser.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAC9B;;OAEG;IAEI,KAAK,CAAU;IAEtB;;OAEG;IAEI,QAAQ,CAAU;IAEzB;;OAEG;IAEI,IAAI,CAAU;IAErB;;OAEG;IAEI,QAAQ,CAAU;IAEzB;;OAEG;IAEI,YAAY,CAAU;CAC7B,CAAA;AAzBO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;iDACxB;AAMf;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;oDACJ;AAMlB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;gDACR;AAMd;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;oDACJ;AAMlB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;wDACA;AA7BjB,kBAAkB;IAD9B,MAAM,EAAE;GACI,kBAAkB,CA8B9B","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@twin.org/entity\";\n\n/**\n * Class defining the storage for user login credentials.\n */\n@entity()\nexport class AuthenticationUser {\n\t/**\n\t * The user e-mail address.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic email!: string;\n\n\t/**\n\t * The encrypted password for the user.\n\t */\n\t@property({ type: \"string\" })\n\tpublic password!: string;\n\n\t/**\n\t * The salt for the password.\n\t */\n\t@property({ type: \"string\" })\n\tpublic salt!: string;\n\n\t/**\n\t * The user identity.\n\t */\n\t@property({ type: \"string\" })\n\tpublic identity!: string;\n\n\t/**\n\t * The users organization.\n\t */\n\t@property({ type: \"string\" })\n\tpublic organization!: string;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export * from "./entities/authenticationUser.js";
4
+ export * from "./models/IAuthHeaderProcessorConfig.js";
5
+ export * from "./models/IAuthHeaderProcessorConstructorOptions.js";
6
+ export * from "./models/IEntityStorageAuthenticationAdminServiceConfig.js";
7
+ export * from "./models/IEntityStorageAuthenticationAdminServiceConstructorOptions.js";
8
+ export * from "./models/IEntityStorageAuthenticationServiceConfig.js";
9
+ export * from "./models/IEntityStorageAuthenticationServiceConstructorOptions.js";
10
+ export * from "./processors/authHeaderProcessor.js";
11
+ export * from "./restEntryPoints.js";
12
+ export * from "./routes/entityStorageAuthenticationRoutes.js";
13
+ export * from "./schema.js";
14
+ export * from "./services/entityStorageAuthenticationAdminService.js";
15
+ export * from "./services/entityStorageAuthenticationService.js";
16
+ export * from "./utils/passwordHelper.js";
17
+ export * from "./utils/tokenHelper.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oDAAoD,CAAC;AACnE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,wEAAwE,CAAC;AACvF,cAAc,uDAAuD,CAAC;AACtE,cAAc,mEAAmE,CAAC;AAClF,cAAc,qCAAqC,CAAC;AACpD,cAAc,sBAAsB,CAAC;AACrC,cAAc,+CAA+C,CAAC;AAC9D,cAAc,aAAa,CAAC;AAC5B,cAAc,uDAAuD,CAAC;AACtE,cAAc,kDAAkD,CAAC;AACjE,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/authenticationUser.js\";\nexport * from \"./models/IAuthHeaderProcessorConfig.js\";\nexport * from \"./models/IAuthHeaderProcessorConstructorOptions.js\";\nexport * from \"./models/IEntityStorageAuthenticationAdminServiceConfig.js\";\nexport * from \"./models/IEntityStorageAuthenticationAdminServiceConstructorOptions.js\";\nexport * from \"./models/IEntityStorageAuthenticationServiceConfig.js\";\nexport * from \"./models/IEntityStorageAuthenticationServiceConstructorOptions.js\";\nexport * from \"./processors/authHeaderProcessor.js\";\nexport * from \"./restEntryPoints.js\";\nexport * from \"./routes/entityStorageAuthenticationRoutes.js\";\nexport * from \"./schema.js\";\nexport * from \"./services/entityStorageAuthenticationAdminService.js\";\nexport * from \"./services/entityStorageAuthenticationService.js\";\nexport * from \"./utils/passwordHelper.js\";\nexport * from \"./utils/tokenHelper.js\";\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=IAuthHeaderProcessorConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IAuthHeaderProcessorConfig.js","sourceRoot":"","sources":["../../../src/models/IAuthHeaderProcessorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the authentication header processor\n */\nexport interface IAuthHeaderProcessorConfig {\n\t/**\n\t * The name of the key to retrieve from the vault for signing JWT.\n\t * @default auth-signing\n\t */\n\tsigningKeyName?: string;\n\n\t/**\n\t * The name of the cookie to use for the token.\n\t * @default access_token\n\t */\n\tcookieName?: string;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IAuthHeaderProcessorConstructorOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IAuthHeaderProcessorConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IAuthHeaderProcessorConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IAuthHeaderProcessorConfig } from \"./IAuthHeaderProcessorConfig.js\";\n\n/**\n * Options for the AuthHeaderProcessor constructor.\n */\nexport interface IAuthHeaderProcessorConstructorOptions {\n\t/**\n\t * The vault for the private keys.\n\t * @default vault\n\t */\n\tvaultConnectorType?: string;\n\n\t/**\n\t * The configuration for the processor.\n\t */\n\tconfig?: IAuthHeaderProcessorConfig;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=IEntityStorageAuthenticationAdminServiceConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEntityStorageAuthenticationAdminServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IEntityStorageAuthenticationAdminServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the entity storage authentication admin service.\n */\nexport interface IEntityStorageAuthenticationAdminServiceConfig {\n\t/**\n\t * The minimum password length.\n\t * @default 8\n\t */\n\tminPasswordLength?: number;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IEntityStorageAuthenticationAdminServiceConstructorOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEntityStorageAuthenticationAdminServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IEntityStorageAuthenticationAdminServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IEntityStorageAuthenticationAdminServiceConfig } from \"./IEntityStorageAuthenticationAdminServiceConfig.js\";\n\n/**\n * Options for the EntityStorageAuthenticationAdminService constructor.\n */\nexport interface IEntityStorageAuthenticationAdminServiceConstructorOptions {\n\t/**\n\t * The entity storage for the users.\n\t * @default authentication-user\n\t */\n\tuserEntityStorageType?: string;\n\n\t/**\n\t * The configuration for the authentication.\n\t */\n\tconfig?: IEntityStorageAuthenticationAdminServiceConfig;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=IEntityStorageAuthenticationServiceConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEntityStorageAuthenticationServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IEntityStorageAuthenticationServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the entity storage authentication service.\n */\nexport interface IEntityStorageAuthenticationServiceConfig {\n\t/**\n\t * The name of the key to retrieve from the vault for signing JWT.\n\t * @default auth-signing\n\t */\n\tsigningKeyName?: string;\n\n\t/**\n\t * The default time to live for the JWT.\n\t * @default 1440\n\t */\n\tdefaultTtlMinutes?: number;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IEntityStorageAuthenticationServiceConstructorOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEntityStorageAuthenticationServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IEntityStorageAuthenticationServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IEntityStorageAuthenticationServiceConfig } from \"./IEntityStorageAuthenticationServiceConfig.js\";\n\n/**\n * Options for the EntityStorageAuthenticationService constructor.\n */\nexport interface IEntityStorageAuthenticationServiceConstructorOptions {\n\t/**\n\t * The entity storage for the users.\n\t * @default authentication-user\n\t */\n\tuserEntityStorageType?: string;\n\n\t/**\n\t * The vault for the private keys.\n\t * @default vault\n\t */\n\tvaultConnectorType?: string;\n\n\t/**\n\t * The admin service.\n\t * @default authentication-admin\n\t */\n\tauthenticationAdminServiceType?: string;\n\n\t/**\n\t * The configuration for the authentication.\n\t */\n\tconfig?: IEntityStorageAuthenticationServiceConfig;\n}\n"]}
@@ -0,0 +1,134 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { HttpErrorHelper } from "@twin.org/api-models";
4
+ import { ContextIdHelper, ContextIdKeys, ContextIdStore } from "@twin.org/context";
5
+ import { BaseError, Coerce, GeneralError, Is } from "@twin.org/core";
6
+ import { VaultConnectorFactory } from "@twin.org/vault-models";
7
+ import { CookieHelper, HeaderTypes, HttpStatusCode } from "@twin.org/web";
8
+ import { TokenHelper } from "../utils/tokenHelper.js";
9
+ /**
10
+ * Handle a JWT token in the authorization header or cookies and validate it to populate request context identity.
11
+ */
12
+ export class AuthHeaderProcessor {
13
+ /**
14
+ * The default name for the access token as a cookie.
15
+ * @internal
16
+ */
17
+ static DEFAULT_COOKIE_NAME = "access_token";
18
+ /**
19
+ * Runtime name for the class.
20
+ */
21
+ static CLASS_NAME = "AuthHeaderProcessor";
22
+ /**
23
+ * The vault for the keys.
24
+ * @internal
25
+ */
26
+ _vaultConnector;
27
+ /**
28
+ * The name of the key to retrieve from the vault for signing JWT.
29
+ * @internal
30
+ */
31
+ _signingKeyName;
32
+ /**
33
+ * The name of the cookie to use for the token.
34
+ * @internal
35
+ */
36
+ _cookieName;
37
+ /**
38
+ * The node identity.
39
+ * @internal
40
+ */
41
+ _nodeId;
42
+ /**
43
+ * Create a new instance of AuthCookiePreProcessor.
44
+ * @param options Options for the processor.
45
+ */
46
+ constructor(options) {
47
+ this._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? "vault");
48
+ this._signingKeyName = options?.config?.signingKeyName ?? "auth-signing";
49
+ this._cookieName = options?.config?.cookieName ?? AuthHeaderProcessor.DEFAULT_COOKIE_NAME;
50
+ }
51
+ /**
52
+ * Returns the class name of the component.
53
+ * @returns The class name of the component.
54
+ */
55
+ className() {
56
+ return AuthHeaderProcessor.CLASS_NAME;
57
+ }
58
+ /**
59
+ * The service needs to be started when the application is initialized.
60
+ * @param nodeLoggingComponentType The node logging component type.
61
+ * @returns Nothing.
62
+ */
63
+ async start(nodeLoggingComponentType) {
64
+ const contextIds = await ContextIdStore.getContextIds();
65
+ ContextIdHelper.guard(contextIds, ContextIdKeys.Node);
66
+ this._nodeId = contextIds[ContextIdKeys.Node];
67
+ }
68
+ /**
69
+ * Pre process the REST request for the specified route.
70
+ * @param request The incoming request.
71
+ * @param response The outgoing response.
72
+ * @param route The route to process.
73
+ * @param contextIds The context IDs of the request.
74
+ * @param processorState The state handed through the processors.
75
+ */
76
+ async pre(request, response, route, contextIds, processorState) {
77
+ if (!Is.empty(route) && !(route.skipAuth ?? false)) {
78
+ try {
79
+ const tokenAndLocation = TokenHelper.extractTokenFromHeaders(request.headers, this._cookieName);
80
+ const headerAndPayload = await TokenHelper.verify(this._vaultConnector, `${this._nodeId}/${this._signingKeyName}`, tokenAndLocation?.token);
81
+ // If tenant id is defined in the context, then it must match the one in the token
82
+ // but both can be undefined in a single tenant context
83
+ if (contextIds?.[ContextIdKeys.Tenant] !== headerAndPayload?.payload?.tid) {
84
+ throw new GeneralError(AuthHeaderProcessor.CLASS_NAME, "tenantIdMismatch");
85
+ }
86
+ contextIds[ContextIdKeys.User] = headerAndPayload.payload?.sub;
87
+ contextIds[ContextIdKeys.Organization] = Coerce.string(headerAndPayload.payload?.org);
88
+ processorState.authToken = tokenAndLocation?.token;
89
+ processorState.authTokenLocation = tokenAndLocation?.location;
90
+ }
91
+ catch (err) {
92
+ const error = BaseError.fromError(err);
93
+ HttpErrorHelper.buildResponse(response, error, HttpStatusCode.unauthorized);
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Post process the REST request for the specified route.
99
+ * @param request The incoming request.
100
+ * @param response The outgoing response.
101
+ * @param route The route to process.
102
+ * @param contextIds The context IDs of the request.
103
+ * @param processorState The state handed through the processors.
104
+ */
105
+ async post(request, response, route, contextIds, processorState) {
106
+ const responseAuthOperation = processorState?.authOperation;
107
+ const responseAuthToken = processorState?.authToken;
108
+ // We don't populate the cookie if the incoming request was from an authorization header.
109
+ if (!Is.empty(route) &&
110
+ Is.stringValue(responseAuthOperation) &&
111
+ processorState.authTokenLocation !== "authorization") {
112
+ if ((responseAuthOperation === "login" || responseAuthOperation === "refresh") &&
113
+ Is.stringValue(responseAuthToken)) {
114
+ response.headers ??= {};
115
+ response.headers[HeaderTypes.SetCookie] = CookieHelper.createCookie(this._cookieName, responseAuthToken, {
116
+ secure: true,
117
+ httpOnly: true,
118
+ sameSite: "None",
119
+ path: "/"
120
+ });
121
+ }
122
+ else if (responseAuthOperation === "logout") {
123
+ response.headers ??= {};
124
+ response.headers[HeaderTypes.SetCookie] = CookieHelper.deleteCookie(this._cookieName, {
125
+ secure: true,
126
+ httpOnly: true,
127
+ sameSite: "None",
128
+ path: "/"
129
+ });
130
+ }
131
+ }
132
+ }
133
+ }
134
+ //# sourceMappingURL=authHeaderProcessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authHeaderProcessor.js","sourceRoot":"","sources":["../../../src/processors/authHeaderProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\tHttpErrorHelper,\n\ttype IBaseRoute,\n\ttype IBaseRouteProcessor,\n\ttype IHttpResponse,\n\ttype IHttpServerRequest\n} from \"@twin.org/api-models\";\nimport {\n\tContextIdHelper,\n\tContextIdKeys,\n\tContextIdStore,\n\ttype IContextIds\n} from \"@twin.org/context\";\nimport { BaseError, Coerce, GeneralError, Is } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { VaultConnectorFactory, type IVaultConnector } from \"@twin.org/vault-models\";\nimport { CookieHelper, HeaderTypes, HttpStatusCode } from \"@twin.org/web\";\nimport type { IAuthHeaderProcessorConstructorOptions } from \"../models/IAuthHeaderProcessorConstructorOptions.js\";\nimport { TokenHelper } from \"../utils/tokenHelper.js\";\n\n/**\n * Handle a JWT token in the authorization header or cookies and validate it to populate request context identity.\n */\nexport class AuthHeaderProcessor implements IBaseRouteProcessor {\n\t/**\n\t * The default name for the access token as a cookie.\n\t * @internal\n\t */\n\tpublic static readonly DEFAULT_COOKIE_NAME: string = \"access_token\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<AuthHeaderProcessor>();\n\n\t/**\n\t * The vault for the keys.\n\t * @internal\n\t */\n\tprivate readonly _vaultConnector: IVaultConnector;\n\n\t/**\n\t * The name of the key to retrieve from the vault for signing JWT.\n\t * @internal\n\t */\n\tprivate readonly _signingKeyName: string;\n\n\t/**\n\t * The name of the cookie to use for the token.\n\t * @internal\n\t */\n\tprivate readonly _cookieName: string;\n\n\t/**\n\t * The node identity.\n\t * @internal\n\t */\n\tprivate _nodeId?: string;\n\n\t/**\n\t * Create a new instance of AuthCookiePreProcessor.\n\t * @param options Options for the processor.\n\t */\n\tconstructor(options?: IAuthHeaderProcessorConstructorOptions) {\n\t\tthis._vaultConnector = VaultConnectorFactory.get(options?.vaultConnectorType ?? \"vault\");\n\t\tthis._signingKeyName = options?.config?.signingKeyName ?? \"auth-signing\";\n\t\tthis._cookieName = options?.config?.cookieName ?? AuthHeaderProcessor.DEFAULT_COOKIE_NAME;\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn AuthHeaderProcessor.CLASS_NAME;\n\t}\n\n\t/**\n\t * The service needs to be started when the application is initialized.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns Nothing.\n\t */\n\tpublic async start(nodeLoggingComponentType?: string): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tContextIdHelper.guard(contextIds, ContextIdKeys.Node);\n\t\tthis._nodeId = contextIds[ContextIdKeys.Node];\n\t}\n\n\t/**\n\t * Pre process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t */\n\tpublic async pre(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tif (!Is.empty(route) && !(route.skipAuth ?? false)) {\n\t\t\ttry {\n\t\t\t\tconst tokenAndLocation = TokenHelper.extractTokenFromHeaders(\n\t\t\t\t\trequest.headers,\n\t\t\t\t\tthis._cookieName\n\t\t\t\t);\n\n\t\t\t\tconst headerAndPayload = await TokenHelper.verify(\n\t\t\t\t\tthis._vaultConnector,\n\t\t\t\t\t`${this._nodeId}/${this._signingKeyName}`,\n\t\t\t\t\ttokenAndLocation?.token\n\t\t\t\t);\n\n\t\t\t\t// If tenant id is defined in the context, then it must match the one in the token\n\t\t\t\t// but both can be undefined in a single tenant context\n\t\t\t\tif (contextIds?.[ContextIdKeys.Tenant] !== headerAndPayload?.payload?.tid) {\n\t\t\t\t\tthrow new GeneralError(AuthHeaderProcessor.CLASS_NAME, \"tenantIdMismatch\");\n\t\t\t\t}\n\n\t\t\t\tcontextIds[ContextIdKeys.User] = headerAndPayload.payload?.sub;\n\t\t\t\tcontextIds[ContextIdKeys.Organization] = Coerce.string(headerAndPayload.payload?.org);\n\n\t\t\t\tprocessorState.authToken = tokenAndLocation?.token;\n\t\t\t\tprocessorState.authTokenLocation = tokenAndLocation?.location;\n\t\t\t} catch (err) {\n\t\t\t\tconst error = BaseError.fromError(err);\n\t\t\t\tHttpErrorHelper.buildResponse(response, error, HttpStatusCode.unauthorized);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Post process the REST request for the specified route.\n\t * @param request The incoming request.\n\t * @param response The outgoing response.\n\t * @param route The route to process.\n\t * @param contextIds The context IDs of the request.\n\t * @param processorState The state handed through the processors.\n\t */\n\tpublic async post(\n\t\trequest: IHttpServerRequest,\n\t\tresponse: IHttpResponse,\n\t\troute: IBaseRoute | undefined,\n\t\tcontextIds: IContextIds,\n\t\tprocessorState: { [id: string]: unknown }\n\t): Promise<void> {\n\t\tconst responseAuthOperation = processorState?.authOperation;\n\t\tconst responseAuthToken = processorState?.authToken;\n\n\t\t// We don't populate the cookie if the incoming request was from an authorization header.\n\t\tif (\n\t\t\t!Is.empty(route) &&\n\t\t\tIs.stringValue(responseAuthOperation) &&\n\t\t\tprocessorState.authTokenLocation !== \"authorization\"\n\t\t) {\n\t\t\tif (\n\t\t\t\t(responseAuthOperation === \"login\" || responseAuthOperation === \"refresh\") &&\n\t\t\t\tIs.stringValue(responseAuthToken)\n\t\t\t) {\n\t\t\t\tresponse.headers ??= {};\n\t\t\t\tresponse.headers[HeaderTypes.SetCookie] = CookieHelper.createCookie(\n\t\t\t\t\tthis._cookieName,\n\t\t\t\t\tresponseAuthToken,\n\t\t\t\t\t{\n\t\t\t\t\t\tsecure: true,\n\t\t\t\t\t\thttpOnly: true,\n\t\t\t\t\t\tsameSite: \"None\",\n\t\t\t\t\t\tpath: \"/\"\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} else if (responseAuthOperation === \"logout\") {\n\t\t\t\tresponse.headers ??= {};\n\t\t\t\tresponse.headers[HeaderTypes.SetCookie] = CookieHelper.deleteCookie(this._cookieName, {\n\t\t\t\t\tsecure: true,\n\t\t\t\t\thttpOnly: true,\n\t\t\t\t\tsameSite: \"None\",\n\t\t\t\t\tpath: \"/\"\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { generateRestRoutesAuthentication, tagsAuthentication } from "./routes/entityStorageAuthenticationRoutes.js";
2
+ export const restEntryPoints = [
3
+ {
4
+ name: "authentication",
5
+ defaultBaseRoute: "authentication",
6
+ tags: tagsAuthentication,
7
+ generateRoutes: generateRestRoutesAuthentication
8
+ }
9
+ ];
10
+ //# sourceMappingURL=restEntryPoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restEntryPoints.js","sourceRoot":"","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,gCAAgC,EAChC,kBAAkB,EAClB,MAAM,+CAA+C,CAAC;AAEvD,MAAM,CAAC,MAAM,eAAe,GAA2B;IACtD;QACC,IAAI,EAAE,gBAAgB;QACtB,gBAAgB,EAAE,gBAAgB;QAClC,IAAI,EAAE,kBAAkB;QACxB,cAAc,EAAE,gCAAgC;KAChD;CACD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IRestRouteEntryPoint } from \"@twin.org/api-models\";\nimport {\n\tgenerateRestRoutesAuthentication,\n\ttagsAuthentication\n} from \"./routes/entityStorageAuthenticationRoutes.js\";\n\nexport const restEntryPoints: IRestRouteEntryPoint[] = [\n\t{\n\t\tname: \"authentication\",\n\t\tdefaultBaseRoute: \"authentication\",\n\t\ttags: tagsAuthentication,\n\t\tgenerateRoutes: generateRestRoutesAuthentication\n\t}\n];\n"]}
@@ -0,0 +1,252 @@
1
+ import { ComponentFactory, Guards } from "@twin.org/core";
2
+ import { HttpStatusCode } from "@twin.org/web";
3
+ /**
4
+ * The source used when communicating about these routes.
5
+ */
6
+ const ROUTES_SOURCE = "authenticationRoutes";
7
+ /**
8
+ * The tag to associate with the routes.
9
+ */
10
+ export const tagsAuthentication = [
11
+ {
12
+ name: "Authentication",
13
+ description: "Authentication endpoints for the REST server."
14
+ }
15
+ ];
16
+ /**
17
+ * The REST routes for authentication.
18
+ * @param baseRouteName Prefix to prepend to the paths.
19
+ * @param componentName The name of the component to use in the routes stored in the ComponentFactory.
20
+ * @returns The generated routes.
21
+ */
22
+ export function generateRestRoutesAuthentication(baseRouteName, componentName) {
23
+ const loginRoute = {
24
+ operationId: "authenticationLogin",
25
+ summary: "Login to the server",
26
+ tag: tagsAuthentication[0].name,
27
+ method: "POST",
28
+ path: `${baseRouteName}/login`,
29
+ handler: async (httpRequestContext, request) => authenticationLogin(httpRequestContext, componentName, request),
30
+ requestType: {
31
+ type: "ILoginRequest",
32
+ examples: [
33
+ {
34
+ id: "loginRequestExample",
35
+ description: "The request to login to the server.",
36
+ request: {
37
+ body: {
38
+ email: "user@example.com",
39
+ password: "MyPassword123!"
40
+ }
41
+ }
42
+ }
43
+ ]
44
+ },
45
+ responseType: [
46
+ {
47
+ type: "ILoginResponse",
48
+ examples: [
49
+ {
50
+ id: "loginResponseExample",
51
+ description: "The response for the login request.",
52
+ response: {
53
+ body: {
54
+ expiry: 1722514341067
55
+ }
56
+ }
57
+ }
58
+ ]
59
+ },
60
+ {
61
+ type: "IUnauthorizedResponse"
62
+ }
63
+ ],
64
+ skipAuth: true
65
+ };
66
+ const logoutRoute = {
67
+ operationId: "authenticationLogout",
68
+ summary: "Logout from the server",
69
+ tag: tagsAuthentication[0].name,
70
+ method: "GET",
71
+ path: `${baseRouteName}/logout`,
72
+ handler: async (httpRequestContext, request) => authenticationLogout(httpRequestContext, componentName, request),
73
+ requestType: {
74
+ type: "ILogoutRequest",
75
+ examples: [
76
+ {
77
+ id: "logoutRequestExample",
78
+ description: "The request to logout from the server.",
79
+ request: {
80
+ query: {
81
+ token: "eyJhbGciOiJIU...sw5c"
82
+ }
83
+ }
84
+ }
85
+ ]
86
+ },
87
+ responseType: [
88
+ {
89
+ type: "INoContentResponse"
90
+ }
91
+ ],
92
+ skipAuth: true
93
+ };
94
+ const refreshTokenRoute = {
95
+ operationId: "authenticationRefreshToken",
96
+ summary: "Refresh an authentication token",
97
+ tag: tagsAuthentication[0].name,
98
+ method: "GET",
99
+ path: `${baseRouteName}/refresh`,
100
+ handler: async (httpRequestContext, request) => authenticationRefreshToken(httpRequestContext, componentName, request),
101
+ requestType: {
102
+ type: "IRefreshTokenRequest",
103
+ examples: [
104
+ {
105
+ id: "refreshTokenRequestExample",
106
+ description: "The request to refresh an auth token.",
107
+ request: {
108
+ query: {
109
+ token: "eyJhbGciOiJIU...sw5c"
110
+ }
111
+ }
112
+ }
113
+ ]
114
+ },
115
+ responseType: [
116
+ {
117
+ type: "IRefreshTokenResponse",
118
+ examples: [
119
+ {
120
+ id: "refreshTokenResponseExample",
121
+ description: "The response for the refresh token request.",
122
+ response: {
123
+ body: {
124
+ expiry: 1722514341067
125
+ }
126
+ }
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ type: "IUnauthorizedResponse"
132
+ }
133
+ ]
134
+ };
135
+ const updatePasswordRoute = {
136
+ operationId: "authenticationUpdatePassword",
137
+ summary: "Update the user's password",
138
+ tag: tagsAuthentication[0].name,
139
+ method: "PUT",
140
+ path: `${baseRouteName}/:email/password`,
141
+ handler: async (httpRequestContext, request) => authenticationUpdatePassword(httpRequestContext, componentName, request),
142
+ requestType: {
143
+ type: "IUpdatePasswordRequest",
144
+ examples: [
145
+ {
146
+ id: "updatePasswordRequestExample",
147
+ description: "The request to update the user's password.",
148
+ request: {
149
+ pathParams: {
150
+ email: "john:example.com"
151
+ },
152
+ body: {
153
+ currentPassword: "MyNewPassword123!",
154
+ newPassword: "MyNewPassword123!"
155
+ }
156
+ }
157
+ }
158
+ ]
159
+ },
160
+ responseType: [
161
+ {
162
+ type: "INoContentResponse"
163
+ },
164
+ {
165
+ type: "IUnauthorizedResponse"
166
+ }
167
+ ]
168
+ };
169
+ return [loginRoute, logoutRoute, refreshTokenRoute, updatePasswordRoute];
170
+ }
171
+ /**
172
+ * Login to the server.
173
+ * @param httpRequestContext The request context for the API.
174
+ * @param componentName The name of the component to use in the routes.
175
+ * @param request The request.
176
+ * @returns The response object with additional http response properties.
177
+ */
178
+ export async function authenticationLogin(httpRequestContext, componentName, request) {
179
+ Guards.object(ROUTES_SOURCE, "request", request);
180
+ Guards.object(ROUTES_SOURCE, "request.body", request.body);
181
+ const component = ComponentFactory.get(componentName);
182
+ const result = await component.login(request.body.email, request.body.password);
183
+ // Need to give a hint to any auth processors about the operation
184
+ // in case they need to manipulate the response
185
+ httpRequestContext.processorState.authOperation = "login";
186
+ httpRequestContext.processorState.authToken = result.token;
187
+ return {
188
+ body: {
189
+ expiry: result.expiry
190
+ }
191
+ };
192
+ }
193
+ /**
194
+ * Logout from the server.
195
+ * @param httpRequestContext The request context for the API.
196
+ * @param componentName The name of the component to use in the routes.
197
+ * @param request The request.
198
+ * @returns The response object with additional http response properties.
199
+ */
200
+ export async function authenticationLogout(httpRequestContext, componentName, request) {
201
+ Guards.object(ROUTES_SOURCE, "request", request);
202
+ const component = ComponentFactory.get(componentName);
203
+ await component.logout(request.query?.token);
204
+ // Need to give a hint to any auth processors about the operation
205
+ // in case they need to manipulate the response
206
+ httpRequestContext.processorState.authOperation = "logout";
207
+ return {
208
+ statusCode: HttpStatusCode.noContent
209
+ };
210
+ }
211
+ /**
212
+ * Refresh the login token.
213
+ * @param httpRequestContext The request context for the API.
214
+ * @param componentName The name of the component to use in the routes.
215
+ * @param request The request.
216
+ * @returns The response object with additional http response properties.
217
+ */
218
+ export async function authenticationRefreshToken(httpRequestContext, componentName, request) {
219
+ Guards.object(ROUTES_SOURCE, "request", request);
220
+ const component = ComponentFactory.get(componentName);
221
+ // If the token is not in the query, then maybe an auth processor has extracted it
222
+ // and stored it in the processor state
223
+ const token = request.query?.token ?? httpRequestContext.processorState.authToken;
224
+ const result = await component.refresh(token);
225
+ // Need to give a hint to any auth processors about the operation
226
+ // in case they need to manipulate the response
227
+ httpRequestContext.processorState.authOperation = "refresh";
228
+ httpRequestContext.processorState.authToken = result.token;
229
+ return {
230
+ body: {
231
+ expiry: result.expiry
232
+ }
233
+ };
234
+ }
235
+ /**
236
+ * Update the user's password.
237
+ * @param httpRequestContext The request context for the API.
238
+ * @param componentName The name of the component to use in the routes.
239
+ * @param request The request.
240
+ * @returns The response object with additional http response properties.
241
+ */
242
+ export async function authenticationUpdatePassword(httpRequestContext, componentName, request) {
243
+ Guards.object(ROUTES_SOURCE, "request", request);
244
+ Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
245
+ Guards.object(ROUTES_SOURCE, "request.body", request.body);
246
+ const component = ComponentFactory.get(componentName);
247
+ await component.updatePassword(request.pathParams.email, request.body.currentPassword, request.body.newPassword);
248
+ return {
249
+ statusCode: HttpStatusCode.noContent
250
+ };
251
+ }
252
+ //# sourceMappingURL=entityStorageAuthenticationRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityStorageAuthenticationRoutes.js","sourceRoot":"","sources":["../../../src/routes/entityStorageAuthenticationRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIAuthenticationComponent,\n\tILoginRequest,\n\tILoginResponse,\n\tILogoutRequest,\n\tIRefreshTokenRequest,\n\tIRefreshTokenResponse,\n\tIUpdatePasswordRequest\n} from \"@twin.org/api-auth-entity-storage-models\";\nimport type {\n\tIHttpRequestContext,\n\tINoContentResponse,\n\tIRestRoute,\n\tIRestRouteResponseOptions,\n\tITag,\n\tIUnauthorizedResponse\n} from \"@twin.org/api-models\";\nimport { ComponentFactory, Guards } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HttpStatusCode } from \"@twin.org/web\";\n\n/**\n * The source used when communicating about these routes.\n */\nconst ROUTES_SOURCE = \"authenticationRoutes\";\n\n/**\n * The tag to associate with the routes.\n */\nexport const tagsAuthentication: ITag[] = [\n\t{\n\t\tname: \"Authentication\",\n\t\tdescription: \"Authentication endpoints for the REST server.\"\n\t}\n];\n\n/**\n * The REST routes for authentication.\n * @param baseRouteName Prefix to prepend to the paths.\n * @param componentName The name of the component to use in the routes stored in the ComponentFactory.\n * @returns The generated routes.\n */\nexport function generateRestRoutesAuthentication(\n\tbaseRouteName: string,\n\tcomponentName: string\n): IRestRoute[] {\n\tconst loginRoute: IRestRoute<ILoginRequest, ILoginResponse> = {\n\t\toperationId: \"authenticationLogin\",\n\t\tsummary: \"Login to the server\",\n\t\ttag: tagsAuthentication[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/login`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tauthenticationLogin(httpRequestContext, componentName, request),\n\t\trequestType: {\n\t\t\ttype: nameof<ILoginRequest>(),\n\t\t\texamples: [\n\t\t\t\t{\n\t\t\t\t\tid: \"loginRequestExample\",\n\t\t\t\t\tdescription: \"The request to login to the server.\",\n\t\t\t\t\trequest: {\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\temail: \"user@example.com\",\n\t\t\t\t\t\t\tpassword: \"MyPassword123!\"\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},\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<ILoginResponse>(),\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"loginResponseExample\",\n\t\t\t\t\t\tdescription: \"The response for the login request.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\texpiry: 1722514341067\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\t{\n\t\t\t\ttype: nameof<IUnauthorizedResponse>()\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\tconst logoutRoute: IRestRoute<ILogoutRequest, INoContentResponse> = {\n\t\toperationId: \"authenticationLogout\",\n\t\tsummary: \"Logout from the server\",\n\t\ttag: tagsAuthentication[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/logout`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tauthenticationLogout(httpRequestContext, componentName, request),\n\t\trequestType: {\n\t\t\ttype: nameof<ILogoutRequest>(),\n\t\t\texamples: [\n\t\t\t\t{\n\t\t\t\t\tid: \"logoutRequestExample\",\n\t\t\t\t\tdescription: \"The request to logout from the server.\",\n\t\t\t\t\trequest: {\n\t\t\t\t\t\tquery: {\n\t\t\t\t\t\t\ttoken: \"eyJhbGciOiJIU...sw5c\"\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},\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<INoContentResponse>()\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\tconst refreshTokenRoute: IRestRoute<IRefreshTokenRequest, IRefreshTokenResponse> = {\n\t\toperationId: \"authenticationRefreshToken\",\n\t\tsummary: \"Refresh an authentication token\",\n\t\ttag: tagsAuthentication[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/refresh`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tauthenticationRefreshToken(httpRequestContext, componentName, request),\n\t\trequestType: {\n\t\t\ttype: nameof<IRefreshTokenRequest>(),\n\t\t\texamples: [\n\t\t\t\t{\n\t\t\t\t\tid: \"refreshTokenRequestExample\",\n\t\t\t\t\tdescription: \"The request to refresh an auth token.\",\n\t\t\t\t\trequest: {\n\t\t\t\t\t\tquery: {\n\t\t\t\t\t\t\ttoken: \"eyJhbGciOiJIU...sw5c\"\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},\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<IRefreshTokenResponse>(),\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"refreshTokenResponseExample\",\n\t\t\t\t\t\tdescription: \"The response for the refresh token request.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\texpiry: 1722514341067\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\t{\n\t\t\t\ttype: nameof<IUnauthorizedResponse>()\n\t\t\t}\n\t\t]\n\t};\n\n\tconst updatePasswordRoute: IRestRoute<IUpdatePasswordRequest, INoContentResponse> = {\n\t\toperationId: \"authenticationUpdatePassword\",\n\t\tsummary: \"Update the user's password\",\n\t\ttag: tagsAuthentication[0].name,\n\t\tmethod: \"PUT\",\n\t\tpath: `${baseRouteName}/:email/password`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tauthenticationUpdatePassword(httpRequestContext, componentName, request),\n\t\trequestType: {\n\t\t\ttype: nameof<IUpdatePasswordRequest>(),\n\t\t\texamples: [\n\t\t\t\t{\n\t\t\t\t\tid: \"updatePasswordRequestExample\",\n\t\t\t\t\tdescription: \"The request to update the user's password.\",\n\t\t\t\t\trequest: {\n\t\t\t\t\t\tpathParams: {\n\t\t\t\t\t\t\temail: \"john:example.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\tcurrentPassword: \"MyNewPassword123!\",\n\t\t\t\t\t\t\tnewPassword: \"MyNewPassword123!\"\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},\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<INoContentResponse>()\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: nameof<IUnauthorizedResponse>()\n\t\t\t}\n\t\t]\n\t};\n\n\treturn [loginRoute, logoutRoute, refreshTokenRoute, updatePasswordRoute];\n}\n\n/**\n * Login to the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function authenticationLogin(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ILoginRequest\n): Promise<ILoginResponse & IRestRouteResponseOptions> {\n\tGuards.object<ILoginRequest>(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object<ILoginRequest[\"body\"]>(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst component = ComponentFactory.get<IAuthenticationComponent>(componentName);\n\tconst result = await component.login(request.body.email, request.body.password);\n\n\t// Need to give a hint to any auth processors about the operation\n\t// in case they need to manipulate the response\n\thttpRequestContext.processorState.authOperation = \"login\";\n\thttpRequestContext.processorState.authToken = result.token;\n\n\treturn {\n\t\tbody: {\n\t\t\texpiry: result.expiry\n\t\t}\n\t};\n}\n\n/**\n * Logout from the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function authenticationLogout(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ILogoutRequest\n): Promise<INoContentResponse & IRestRouteResponseOptions> {\n\tGuards.object<ILogoutRequest>(ROUTES_SOURCE, nameof(request), request);\n\n\tconst component = ComponentFactory.get<IAuthenticationComponent>(componentName);\n\tawait component.logout(request.query?.token);\n\n\t// Need to give a hint to any auth processors about the operation\n\t// in case they need to manipulate the response\n\thttpRequestContext.processorState.authOperation = \"logout\";\n\n\treturn {\n\t\tstatusCode: HttpStatusCode.noContent\n\t};\n}\n\n/**\n * Refresh the login token.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function authenticationRefreshToken(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IRefreshTokenRequest\n): Promise<IRefreshTokenResponse & IRestRouteResponseOptions> {\n\tGuards.object<IRefreshTokenRequest>(ROUTES_SOURCE, nameof(request), request);\n\n\tconst component = ComponentFactory.get<IAuthenticationComponent>(componentName);\n\n\t// If the token is not in the query, then maybe an auth processor has extracted it\n\t// and stored it in the processor state\n\tconst token = request.query?.token ?? (httpRequestContext.processorState.authToken as string);\n\tconst result = await component.refresh(token);\n\n\t// Need to give a hint to any auth processors about the operation\n\t// in case they need to manipulate the response\n\thttpRequestContext.processorState.authOperation = \"refresh\";\n\thttpRequestContext.processorState.authToken = result.token;\n\n\treturn {\n\t\tbody: {\n\t\t\texpiry: result.expiry\n\t\t}\n\t};\n}\n\n/**\n * Update the user's password.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function authenticationUpdatePassword(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: IUpdatePasswordRequest\n): Promise<INoContentResponse> {\n\tGuards.object<IUpdatePasswordRequest>(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object<IUpdatePasswordRequest[\"pathParams\"]>(\n\t\tROUTES_SOURCE,\n\t\tnameof(request.pathParams),\n\t\trequest.pathParams\n\t);\n\tGuards.object<IUpdatePasswordRequest[\"body\"]>(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst component = ComponentFactory.get<IAuthenticationComponent>(componentName);\n\n\tawait component.updatePassword(\n\t\trequest.pathParams.email,\n\t\trequest.body.currentPassword,\n\t\trequest.body.newPassword\n\t);\n\n\treturn {\n\t\tstatusCode: HttpStatusCode.noContent\n\t};\n}\n"]}
@@ -0,0 +1,11 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { EntitySchemaFactory, EntitySchemaHelper } from "@twin.org/entity";
4
+ import { AuthenticationUser } from "./entities/authenticationUser.js";
5
+ /**
6
+ * Initialize the schema for the authentication service.
7
+ */
8
+ export function initSchema() {
9
+ EntitySchemaFactory.register("AuthenticationUser", () => EntitySchemaHelper.getSchema(AuthenticationUser));
10
+ }
11
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE;;GAEG;AACH,MAAM,UAAU,UAAU;IACzB,mBAAmB,CAAC,QAAQ,uBAA+B,GAAG,EAAE,CAC/D,kBAAkB,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAChD,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { EntitySchemaFactory, EntitySchemaHelper } from \"@twin.org/entity\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { AuthenticationUser } from \"./entities/authenticationUser.js\";\n\n/**\n * Initialize the schema for the authentication service.\n */\nexport function initSchema(): void {\n\tEntitySchemaFactory.register(nameof<AuthenticationUser>(), () =>\n\t\tEntitySchemaHelper.getSchema(AuthenticationUser)\n\t);\n}\n"]}