@tstdl/base 0.93.78 → 0.93.81

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 (39) hide show
  1. package/api/server/gateway.js +1 -1
  2. package/authentication/authentication.api.d.ts +9 -0
  3. package/authentication/authentication.api.js +3 -0
  4. package/authentication/client/authentication.service.d.ts +23 -15
  5. package/authentication/client/authentication.service.js +30 -21
  6. package/authentication/index.d.ts +1 -0
  7. package/authentication/index.js +1 -0
  8. package/authentication/models/authentication-credentials.model.d.ts +2 -2
  9. package/authentication/models/authentication-credentials.model.js +5 -5
  10. package/authentication/models/authentication-session.model.d.ts +2 -2
  11. package/authentication/models/authentication-session.model.js +3 -3
  12. package/authentication/models/subject.model.js +5 -3
  13. package/authentication/models/token-payload-base.model.d.ts +5 -1
  14. package/authentication/models/token-payload-base.model.js +10 -2
  15. package/authentication/models/token.model.d.ts +9 -1
  16. package/authentication/server/authentication-ancillary.service.d.ts +12 -15
  17. package/authentication/server/authentication-ancillary.service.js +3 -0
  18. package/authentication/server/authentication.api-controller.js +5 -5
  19. package/authentication/server/authentication.audit.d.ts +7 -5
  20. package/authentication/server/authentication.service.d.ts +32 -22
  21. package/authentication/server/authentication.service.js +116 -65
  22. package/authentication/server/drizzle/{0001_condemned_pretty_boy.sql → 0000_violet_callisto.sql} +34 -5
  23. package/authentication/server/drizzle/meta/0000_snapshot.json +500 -6
  24. package/authentication/server/drizzle/meta/_journal.json +2 -9
  25. package/authentication/types.d.ts +6 -0
  26. package/authentication/types.js +1 -0
  27. package/document-management/server/drizzle/{0000_ordinary_pretty_boy.sql → 0000_glamorous_lorna_dane.sql} +96 -76
  28. package/document-management/server/drizzle/meta/0000_snapshot.json +360 -142
  29. package/document-management/server/drizzle/meta/_journal.json +2 -16
  30. package/examples/api/authentication.js +3 -2
  31. package/examples/api/custom-authentication.js +11 -9
  32. package/orm/server/drizzle/schema-converter.js +53 -32
  33. package/package.json +1 -1
  34. package/authentication/server/drizzle/0000_calm_warlock.sql +0 -28
  35. package/authentication/server/drizzle/meta/0001_snapshot.json +0 -651
  36. package/document-management/server/drizzle/0001_lyrical_wong.sql +0 -123
  37. package/document-management/server/drizzle/0002_round_warbird.sql +0 -1
  38. package/document-management/server/drizzle/meta/0001_snapshot.json +0 -2728
  39. package/document-management/server/drizzle/meta/0002_snapshot.json +0 -2722
@@ -206,7 +206,7 @@ let ApiGateway = ApiGateway_1 = class ApiGateway {
206
206
  path: context.request.url.pathname,
207
207
  ipAddress: context.request.ip,
208
208
  userAgent: context.request.headers.tryGetSingle('User-Agent') ?? null,
209
- sessionId: token?.payload.sessionId ?? null,
209
+ sessionId: token?.payload.session ?? null,
210
210
  },
211
211
  });
212
212
  },
@@ -27,6 +27,7 @@ export declare const authenticationApiDefinition: {
27
27
  resource: string;
28
28
  method: "POST";
29
29
  parameters: ObjectSchema<{
30
+ readonly tenantId: string | undefined;
30
31
  readonly subject: string;
31
32
  readonly secret: string;
32
33
  readonly data: undefined;
@@ -87,6 +88,7 @@ export declare const authenticationApiDefinition: {
87
88
  resource: string;
88
89
  method: "POST";
89
90
  parameters: ObjectSchema<{
91
+ readonly tenantId: string | undefined;
90
92
  readonly subject: string;
91
93
  readonly currentSecret: string;
92
94
  readonly newSecret: string;
@@ -98,6 +100,7 @@ export declare const authenticationApiDefinition: {
98
100
  resource: string;
99
101
  method: "POST";
100
102
  parameters: ObjectSchema<{
103
+ readonly tenantId: string | undefined;
101
104
  readonly subject: string;
102
105
  readonly data: undefined;
103
106
  }>;
@@ -146,6 +149,7 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
146
149
  resource: string;
147
150
  method: "POST";
148
151
  parameters: ObjectSchema<{
152
+ readonly tenantId: string | undefined;
149
153
  readonly subject: string;
150
154
  readonly secret: string;
151
155
  readonly data: AuthenticationData;
@@ -206,6 +210,7 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
206
210
  resource: string;
207
211
  method: "POST";
208
212
  parameters: ObjectSchema<{
213
+ readonly tenantId: string | undefined;
209
214
  readonly subject: string;
210
215
  readonly currentSecret: string;
211
216
  readonly newSecret: string;
@@ -217,6 +222,7 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
217
222
  resource: string;
218
223
  method: "POST";
219
224
  parameters: ObjectSchema<{
225
+ readonly tenantId: string | undefined;
220
226
  readonly subject: string;
221
227
  readonly data: AdditionalInitSecretResetData;
222
228
  }>;
@@ -260,6 +266,7 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
260
266
  resource: string;
261
267
  method: "POST";
262
268
  parameters: ObjectSchema<{
269
+ readonly tenantId: string | undefined;
263
270
  readonly subject: string;
264
271
  readonly secret: string;
265
272
  readonly data: AuthenticationData;
@@ -320,6 +327,7 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
320
327
  resource: string;
321
328
  method: "POST";
322
329
  parameters: ObjectSchema<{
330
+ readonly tenantId: string | undefined;
323
331
  readonly subject: string;
324
332
  readonly currentSecret: string;
325
333
  readonly newSecret: string;
@@ -331,6 +339,7 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
331
339
  resource: string;
332
340
  method: "POST";
333
341
  parameters: ObjectSchema<{
342
+ readonly tenantId: string | undefined;
334
343
  readonly subject: string;
335
344
  readonly data: AdditionalInitSecretResetData;
336
345
  }>;
@@ -48,6 +48,7 @@ export function getAuthenticationApiEndpointsDefinition(additionalTokenPayloadSc
48
48
  resource: 'token',
49
49
  method: 'POST',
50
50
  parameters: explicitObject({
51
+ tenantId: optional(string()),
51
52
  subject: string(),
52
53
  secret: string(),
53
54
  data: authenticationDataSchema,
@@ -108,6 +109,7 @@ export function getAuthenticationApiEndpointsDefinition(additionalTokenPayloadSc
108
109
  resource: 'secret/change',
109
110
  method: 'POST',
110
111
  parameters: explicitObject({
112
+ tenantId: optional(string()),
111
113
  subject: string(),
112
114
  currentSecret: string(),
113
115
  newSecret: string(),
@@ -119,6 +121,7 @@ export function getAuthenticationApiEndpointsDefinition(additionalTokenPayloadSc
119
121
  resource: 'secret/init-reset',
120
122
  method: 'POST',
121
123
  parameters: explicitObject({
124
+ tenantId: optional(string()),
122
125
  subject: string(),
123
126
  data: additionalInitSecretResetDataSchema,
124
127
  }),
@@ -2,6 +2,7 @@ import type { AfterResolve } from '../../injector/index.js';
2
2
  import { afterResolve } from '../../injector/index.js';
3
3
  import type { Record } from '../../types/index.js';
4
4
  import type { SecretCheckResult, TokenPayload } from '../models/index.js';
5
+ import type { SubjectInput } from '../types.js';
5
6
  /**
6
7
  * Handles authentication on client side.
7
8
  *
@@ -35,10 +36,12 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
35
36
  readonly token: import("../../signals/api.js").WritableSignal<TokenPayload<AdditionalTokenPayload> | undefined>;
36
37
  /** Whether the user is logged in */
37
38
  readonly isLoggedIn: import("../../signals/api.js").Signal<boolean>;
38
- /** Current subject */
39
- readonly subject: import("../../signals/api.js").Signal<string | undefined>;
40
39
  /** Current session id */
41
40
  readonly sessionId: import("../../signals/api.js").Signal<string | undefined>;
41
+ /** Current tenant id */
42
+ readonly tenantId: import("../../signals/api.js").Signal<string | undefined>;
43
+ /** Current subject */
44
+ readonly subjectId: import("../../signals/api.js").Signal<string | undefined>;
42
45
  /** Current impersonator */
43
46
  readonly impersonator: import("../../signals/api.js").Signal<string | undefined>;
44
47
  /** Whether the user is impersonated */
@@ -50,9 +53,9 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
50
53
  /** Emits when a valid token is available (not undefined and not expired) */
51
54
  readonly validToken$: import("rxjs").Observable<Exclude<TokenPayload<AdditionalTokenPayload>, void | undefined>>;
52
55
  /** Current subject */
53
- readonly subject$: import("rxjs").Observable<string | undefined>;
56
+ readonly subjectId$: import("rxjs").Observable<string | undefined>;
54
57
  /** Emits when subject is available */
55
- readonly definedSubject$: import("rxjs").Observable<string>;
58
+ readonly definedSubjectId$: import("rxjs").Observable<string>;
56
59
  /** Current session id */
57
60
  readonly sessionId$: import("rxjs").Observable<string | undefined>;
58
61
  /** Emits when session id is available */
@@ -70,16 +73,21 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
70
73
  * @throws Will throw if token is not available
71
74
  */
72
75
  get definedToken(): TokenPayload<AdditionalTokenPayload>;
73
- /**
74
- * Get current subject or throw if not available
75
- * @throws Will throw if subject is not available
76
- */
77
- get definedSubject(): string;
78
76
  /**
79
77
  * Get current session id or throw if not available
80
78
  * @throws Will throw if session id is not available
81
79
  */
82
80
  get definedSessionId(): string;
81
+ /**
82
+ * Get current tenant id or throw if not available
83
+ * @throws Will throw if tenant id is not available
84
+ */
85
+ get definedTenantId(): string;
86
+ /**
87
+ * Get current subject or throw if not available
88
+ * @throws Will throw if subject is not available
89
+ */
90
+ get definedSubject(): string;
83
91
  /** Whether a valid token is available (not undefined and not expired) */
84
92
  get hasValidToken(): boolean;
85
93
  constructor();
@@ -106,11 +114,11 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
106
114
  setAdditionalData(data: AuthenticationData): void;
107
115
  /**
108
116
  * Login with subject and secret
109
- * @param subject The subject to login with
117
+ * @param subjectInput The subject to login with
110
118
  * @param secret The secret to login with
111
119
  * @param data Additional authentication data
112
120
  */
113
- login(subject: string, secret: string, data?: AuthenticationData): Promise<void>;
121
+ login(subjectInput: SubjectInput, secret: string, data?: AuthenticationData): Promise<void>;
114
122
  /**
115
123
  * Logout from the current session.
116
124
  * This will attempt to end the session on the server and then clear local credentials.
@@ -139,17 +147,17 @@ export declare class AuthenticationClientService<AdditionalTokenPayload extends
139
147
  unimpersonate(data?: AuthenticationData): Promise<void>;
140
148
  /**
141
149
  * Change the secret for a subject.
142
- * @param subject The subject to change the secret for
150
+ * @param subjectInput The subject to change the secret for
143
151
  * @param currentSecret The current secret
144
152
  * @param newSecret The new secret
145
153
  */
146
- changeSecret(subject: string, currentSecret: string, newSecret: string): Promise<void>;
154
+ changeSecret(subjectInput: SubjectInput, currentSecret: string, newSecret: string): Promise<void>;
147
155
  /**
148
156
  * Initialize a secret reset.
149
- * @param subject The subject to reset the secret for
157
+ * @param subjectInput The subject to reset the secret for
150
158
  * @param data Additional data for secret reset
151
159
  */
152
- initResetSecret(subject: string, data: AdditionalInitSecretResetData): Promise<void>;
160
+ initResetSecret(subjectInput: SubjectInput, data: AdditionalInitSecretResetData): Promise<void>;
153
161
  /**
154
162
  * Reset a secret using a reset token.
155
163
  * @param token The secret reset token
@@ -78,10 +78,12 @@ let AuthenticationClientService = class AuthenticationClientService {
78
78
  token = signal(undefined);
79
79
  /** Whether the user is logged in */
80
80
  isLoggedIn = computed(() => isDefined(this.token()));
81
- /** Current subject */
82
- subject = computed(() => this.token()?.subject);
83
81
  /** Current session id */
84
- sessionId = computed(() => this.token()?.sessionId);
82
+ sessionId = computed(() => this.token()?.session);
83
+ /** Current tenant id */
84
+ tenantId = computed(() => this.token()?.tenant);
85
+ /** Current subject */
86
+ subjectId = computed(() => this.token()?.subject);
85
87
  /** Current impersonator */
86
88
  impersonator = computed(() => this.token()?.impersonator);
87
89
  /** Whether the user is impersonated */
@@ -93,9 +95,9 @@ let AuthenticationClientService = class AuthenticationClientService {
93
95
  /** Emits when a valid token is available (not undefined and not expired) */
94
96
  validToken$ = this.definedToken$.pipe(filter((token) => token.exp > this.estimatedServerTimestampSeconds()));
95
97
  /** Current subject */
96
- subject$ = toObservable(this.subject);
98
+ subjectId$ = toObservable(this.subjectId);
97
99
  /** Emits when subject is available */
98
- definedSubject$ = this.subject$.pipe(filter(isDefined));
100
+ definedSubjectId$ = this.subjectId$.pipe(filter(isDefined));
99
101
  /** Current session id */
100
102
  sessionId$ = toObservable(this.sessionId);
101
103
  /** Emits when session id is available */
@@ -123,6 +125,20 @@ let AuthenticationClientService = class AuthenticationClientService {
123
125
  get definedToken() {
124
126
  return assertDefinedPass(this.token(), 'No token available.');
125
127
  }
128
+ /**
129
+ * Get current session id or throw if not available
130
+ * @throws Will throw if session id is not available
131
+ */
132
+ get definedSessionId() {
133
+ return this.definedToken.session;
134
+ }
135
+ /**
136
+ * Get current tenant id or throw if not available
137
+ * @throws Will throw if tenant id is not available
138
+ */
139
+ get definedTenantId() {
140
+ return this.definedToken.tenant;
141
+ }
126
142
  /**
127
143
  * Get current subject or throw if not available
128
144
  * @throws Will throw if subject is not available
@@ -130,13 +146,6 @@ let AuthenticationClientService = class AuthenticationClientService {
130
146
  get definedSubject() {
131
147
  return this.definedToken.subject;
132
148
  }
133
- /**
134
- * Get current session id or throw if not available
135
- * @throws Will throw if session id is not available
136
- */
137
- get definedSessionId() {
138
- return this.definedToken.sessionId;
139
- }
140
149
  /** Whether a valid token is available (not undefined and not expired) */
141
150
  get hasValidToken() {
142
151
  return (this.token()?.exp ?? 0) > this.estimatedServerTimestampSeconds();
@@ -184,16 +193,16 @@ let AuthenticationClientService = class AuthenticationClientService {
184
193
  }
185
194
  /**
186
195
  * Login with subject and secret
187
- * @param subject The subject to login with
196
+ * @param subjectInput The subject to login with
188
197
  * @param secret The secret to login with
189
198
  * @param data Additional authentication data
190
199
  */
191
- async login(subject, secret, data) {
200
+ async login(subjectInput, secret, data) {
192
201
  if (isDefined(data)) {
193
202
  this.setAdditionalData(data);
194
203
  }
195
204
  const [token] = await Promise.all([
196
- this.client.login({ subject, secret, data: this.authenticationData }),
205
+ this.client.login({ tenantId: subjectInput.tenantId, subject: subjectInput.subject, secret, data: this.authenticationData }),
197
206
  this.syncClock(),
198
207
  ]);
199
208
  this.setNewToken(token);
@@ -291,20 +300,20 @@ let AuthenticationClientService = class AuthenticationClientService {
291
300
  }
292
301
  /**
293
302
  * Change the secret for a subject.
294
- * @param subject The subject to change the secret for
303
+ * @param subjectInput The subject to change the secret for
295
304
  * @param currentSecret The current secret
296
305
  * @param newSecret The new secret
297
306
  */
298
- async changeSecret(subject, currentSecret, newSecret) {
299
- await this.client.changeSecret({ subject, currentSecret, newSecret });
307
+ async changeSecret(subjectInput, currentSecret, newSecret) {
308
+ await this.client.changeSecret({ tenantId: subjectInput.tenantId, subject: subjectInput.subject, currentSecret, newSecret });
300
309
  }
301
310
  /**
302
311
  * Initialize a secret reset.
303
- * @param subject The subject to reset the secret for
312
+ * @param subjectInput The subject to reset the secret for
304
313
  * @param data Additional data for secret reset
305
314
  */
306
- async initResetSecret(subject, data) {
307
- await this.client.initSecretReset({ subject, data });
315
+ async initResetSecret(subjectInput, data) {
316
+ await this.client.initSecretReset({ tenantId: subjectInput.tenantId, subject: subjectInput.subject, data });
308
317
  }
309
318
  /**
310
319
  * Reset a secret using a reset token.
@@ -7,3 +7,4 @@ export * from './authentication.api.js';
7
7
  export * from './client/index.js';
8
8
  export * from './errors/index.js';
9
9
  export * from './models/index.js';
10
+ export * from './types.js';
@@ -7,3 +7,4 @@ export * from './authentication.api.js';
7
7
  export * from './client/index.js';
8
8
  export * from './errors/index.js';
9
9
  export * from './models/index.js';
10
+ export * from './types.js';
@@ -1,5 +1,5 @@
1
- import { Entity, type Uuid } from '../../orm/index.js';
2
- export declare class AuthenticationCredentials extends Entity {
1
+ import { TenantEntity, type Uuid } from '../../orm/index.js';
2
+ export declare class AuthenticationCredentials extends TenantEntity {
3
3
  subject: Uuid;
4
4
  hashVersion: number;
5
5
  /**
@@ -7,10 +7,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { Entity, Reference, Table, Unique, UuidProperty } from '../../orm/index.js';
10
+ import { Table, TenantEntity, TenantReference, Unique, UuidProperty } from '../../orm/index.js';
11
11
  import { Integer, Uint8ArrayProperty } from '../../schema/index.js';
12
12
  import { Subject } from './subject.model.js';
13
- let AuthenticationCredentials = class AuthenticationCredentials extends Entity {
13
+ let AuthenticationCredentials = class AuthenticationCredentials extends TenantEntity {
14
14
  subject;
15
15
  hashVersion;
16
16
  /**
@@ -23,8 +23,7 @@ let AuthenticationCredentials = class AuthenticationCredentials extends Entity {
23
23
  hash;
24
24
  };
25
25
  __decorate([
26
- Reference(() => Subject),
27
- Unique(),
26
+ TenantReference(() => Subject),
28
27
  UuidProperty(),
29
28
  __metadata("design:type", String)
30
29
  ], AuthenticationCredentials.prototype, "subject", void 0);
@@ -41,6 +40,7 @@ __decorate([
41
40
  __metadata("design:type", Uint8Array)
42
41
  ], AuthenticationCredentials.prototype, "hash", void 0);
43
42
  AuthenticationCredentials = __decorate([
44
- Table('credentials', { schema: 'authentication' })
43
+ Table('credentials', { schema: 'authentication' }),
44
+ Unique(['tenantId', 'subject'])
45
45
  ], AuthenticationCredentials);
46
46
  export { AuthenticationCredentials };
@@ -1,6 +1,6 @@
1
1
  import type { Timestamp, Uuid } from '../../orm/index.js';
2
- import { Entity } from '../../orm/index.js';
3
- export declare class AuthenticationSession extends Entity {
2
+ import { TenantEntity } from '../../orm/index.js';
3
+ export declare class AuthenticationSession extends TenantEntity {
4
4
  subject: Uuid;
5
5
  begin: Timestamp;
6
6
  end: Timestamp;
@@ -7,10 +7,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { Entity, Reference, Table, TimestampProperty, UuidProperty } from '../../orm/index.js';
10
+ import { Table, TenantEntity, TenantReference, TimestampProperty, UuidProperty } from '../../orm/index.js';
11
11
  import { Integer, Uint8ArrayProperty } from '../../schema/index.js';
12
12
  import { Subject } from './subject.model.js';
13
- let AuthenticationSession = class AuthenticationSession extends Entity {
13
+ let AuthenticationSession = class AuthenticationSession extends TenantEntity {
14
14
  subject;
15
15
  begin;
16
16
  end;
@@ -25,7 +25,7 @@ let AuthenticationSession = class AuthenticationSession extends Entity {
25
25
  refreshTokenHash;
26
26
  };
27
27
  __decorate([
28
- Reference(() => Subject),
28
+ TenantReference(() => Subject),
29
29
  UuidProperty(),
30
30
  __metadata("design:type", String)
31
31
  ], AuthenticationSession.prototype, "subject", void 0);
@@ -35,25 +35,27 @@ __decorate([
35
35
  __metadata("design:type", String)
36
36
  ], Subject.prototype, "displayName", void 0);
37
37
  __decorate([
38
- Unique(),
39
38
  TenantReference(() => SystemAccount),
40
39
  UuidProperty({ nullable: true }),
41
40
  __metadata("design:type", Object)
42
41
  ], Subject.prototype, "systemAccountId", void 0);
43
42
  __decorate([
44
- Unique(),
45
43
  TenantReference(() => User),
46
44
  UuidProperty({ nullable: true }),
47
45
  __metadata("design:type", Object)
48
46
  ], Subject.prototype, "userId", void 0);
49
47
  __decorate([
50
- Unique(),
51
48
  TenantReference(() => ServiceAccount),
52
49
  UuidProperty({ nullable: true }),
53
50
  __metadata("design:type", Object)
54
51
  ], Subject.prototype, "serviceAccountId", void 0);
55
52
  Subject = __decorate([
56
53
  Table('subject', { schema: 'authentication' }),
54
+ Unique(['id']) // for external systems that might not support composite identities
55
+ ,
56
+ Unique(['tenantId', 'systemAccountId']),
57
+ Unique(['tenantId', 'userId']),
58
+ Unique(['tenantId', 'serviceAccountId']),
57
59
  Check('authentication_subject_reference_check', (table) => exclusiveNotNull(table.systemAccountId, table.userId, table.serviceAccountId))
58
60
  ], Subject);
59
61
  export { Subject };
@@ -21,7 +21,11 @@ export declare class TokenPayloadBase {
21
21
  /**
22
22
  * The id of the session.
23
23
  */
24
- sessionId: string;
24
+ session: string;
25
+ /**
26
+ * The tenant id.
27
+ */
28
+ tenant: string;
25
29
  /**
26
30
  * The subject of the token.
27
31
  */
@@ -31,7 +31,11 @@ export class TokenPayloadBase {
31
31
  /**
32
32
  * The id of the session.
33
33
  */
34
- sessionId;
34
+ session;
35
+ /**
36
+ * The tenant id.
37
+ */
38
+ tenant;
35
39
  /**
36
40
  * The subject of the token.
37
41
  */
@@ -60,7 +64,11 @@ __decorate([
60
64
  __decorate([
61
65
  StringProperty(),
62
66
  __metadata("design:type", String)
63
- ], TokenPayloadBase.prototype, "sessionId", void 0);
67
+ ], TokenPayloadBase.prototype, "session", void 0);
68
+ __decorate([
69
+ StringProperty(),
70
+ __metadata("design:type", String)
71
+ ], TokenPayloadBase.prototype, "tenant", void 0);
64
72
  __decorate([
65
73
  StringProperty(),
66
74
  __metadata("design:type", String)
@@ -22,6 +22,10 @@ export type RefreshToken = JwtToken<{
22
22
  * Expiration timestamp in seconds.
23
23
  */
24
24
  exp: number;
25
+ /**
26
+ * The tenant id.
27
+ */
28
+ tenant: string;
25
29
  /**
26
30
  * The subject of the token.
27
31
  */
@@ -33,7 +37,7 @@ export type RefreshToken = JwtToken<{
33
37
  /**
34
38
  * The id of the session.
35
39
  */
36
- sessionId: string;
40
+ session: string;
37
41
  /**
38
42
  * The secret to use for refreshing the token.
39
43
  */
@@ -44,6 +48,10 @@ export type SecretResetToken = JwtToken<{
44
48
  * Expiration timestamp in seconds.
45
49
  */
46
50
  exp: number;
51
+ /**
52
+ * The tenant id.
53
+ */
54
+ tenant: string;
47
55
  /**
48
56
  * The subject for which to reset the secret.
49
57
  */
@@ -1,7 +1,8 @@
1
1
  import { type EnumType } from '../../enumeration/enumeration.js';
2
2
  import type { Record } from '../../types/index.js';
3
- import type { TokenPayload } from '../index.js';
3
+ import { Subject, type TokenPayload } from '../models/index.js';
4
4
  import type { InitSecretResetData } from '../models/init-secret-reset-data.model.js';
5
+ import type { SubjectInput } from '../types.js';
5
6
  export declare const GetTokenPayloadContextAction: {
6
7
  readonly GetToken: "get-token";
7
8
  readonly Refresh: "refresh";
@@ -13,13 +14,6 @@ export type GetTokenPayloadContext = {
13
14
  */
14
15
  action: GetTokenPayloadContextAction;
15
16
  };
16
- export type ResolveSubjectResult = {
17
- success: true;
18
- subject: string;
19
- } | {
20
- success: false;
21
- subject?: undefined;
22
- };
23
17
  /**
24
18
  * Ancillary service for authentication to hook into the authentication process.
25
19
  *
@@ -28,14 +22,17 @@ export type ResolveSubjectResult = {
28
22
  * @param AdditionalInitSecretResetData Type of additional secret reset data
29
23
  */
30
24
  export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayload extends Record = Record<never>, AuthenticationData = void, AdditionalInitSecretResetData = void> {
25
+ readonly subjectRepository: import("../../orm/server/repository.js").EntityRepository<Subject>;
31
26
  /**
32
- * Resolve a provided subject to the actual subject used for authentication.
27
+ * Resolve a provided subject (like what was entered into login form) to all matching actual subjects.
33
28
  * Useful for example if you want to be able to login via mail but actual subject is the user id.
34
- * @param providedSubject The subject provided by the user, e.g. an email address.
35
- * @returns An object with success flag and the resolved subject if successful.
36
- * If the subject cannot be resolved, return an object with success set to false.
29
+ *
30
+ * If multiple subjects are found (like same mail in multiple tenants), all should be returned.
31
+ * If no subjects are found, an empty array should be returned.
32
+ * @param data The subject provided by the user, e.g. an email address and tenantId if available (for example by tenant specific subdomains).
33
+ * @returns An array of resolved subjects.
37
34
  */
38
- abstract resolveSubject(providedSubject: string): ResolveSubjectResult | Promise<ResolveSubjectResult>;
35
+ abstract resolveSubjects(data: SubjectInput): Promise<Subject[]>;
39
36
  /**
40
37
  * Get the additional token payload for a subject.
41
38
  * @param subject The subject for which to get the payload.
@@ -43,7 +40,7 @@ export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayl
43
40
  * @param context Context for getting the token payload.
44
41
  * @returns The additional token payload.
45
42
  */
46
- abstract getTokenPayload(subject: string, authenticationData: AuthenticationData, context: GetTokenPayloadContext): AdditionalTokenPayload | Promise<AdditionalTokenPayload>;
43
+ abstract getTokenPayload(subject: Subject, authenticationData: AuthenticationData, context: GetTokenPayloadContext): AdditionalTokenPayload | Promise<AdditionalTokenPayload>;
47
44
  /**
48
45
  * Handle the initialization of a secret reset.
49
46
  * @param data Data for initializing the secret reset.
@@ -56,5 +53,5 @@ export declare abstract class AuthenticationAncillaryService<AdditionalTokenPayl
56
53
  * @param authenticationData Additional authentication data.
57
54
  * @returns Whether impersonation is allowed.
58
55
  */
59
- abstract canImpersonate(token: TokenPayload<AdditionalTokenPayload>, subject: string, authenticationData: AuthenticationData): boolean | Promise<boolean>;
56
+ abstract canImpersonate(token: TokenPayload<AdditionalTokenPayload>, subject: Subject, authenticationData: AuthenticationData): boolean | Promise<boolean>;
60
57
  }
@@ -1,4 +1,6 @@
1
1
  import { defineEnum } from '../../enumeration/enumeration.js';
2
+ import { injectRepository } from '../../orm/server/repository.js';
3
+ import { Subject } from '../models/index.js';
2
4
  export const GetTokenPayloadContextAction = defineEnum('GetTokenPayloadContextAction', {
3
5
  GetToken: 'get-token',
4
6
  Refresh: 'refresh',
@@ -11,4 +13,5 @@ export const GetTokenPayloadContextAction = defineEnum('GetTokenPayloadContextAc
11
13
  * @param AdditionalInitSecretResetData Type of additional secret reset data
12
14
  */
13
15
  export class AuthenticationAncillaryService {
16
+ subjectRepository = injectRepository(Subject);
14
17
  }
@@ -34,7 +34,7 @@ let AuthenticationApiController = class AuthenticationApiController {
34
34
  * @returns The token result.
35
35
  */
36
36
  async login({ parameters, getAuditor }) {
37
- const result = await this.authenticationService.login(parameters.subject, parameters.secret, parameters.data, await getAuditor());
37
+ const result = await this.authenticationService.login({ tenantId: parameters.tenantId, subject: parameters.subject }, parameters.secret, parameters.data, await getAuditor());
38
38
  return this.getTokenResponse(result);
39
39
  }
40
40
  /**
@@ -81,13 +81,13 @@ let AuthenticationApiController = class AuthenticationApiController {
81
81
  try {
82
82
  const tokenString = tryGetAuthorizationTokenStringFromRequest(request) ?? '';
83
83
  const token = await this.authenticationService.validateToken(tokenString);
84
- sessionId = token.payload.sessionId;
84
+ sessionId = token.payload.session;
85
85
  }
86
86
  catch (error) {
87
87
  try {
88
88
  const refreshTokenString = tryGetAuthorizationTokenStringFromRequest(request, 'refreshToken', true) ?? '';
89
89
  const refreshToken = await this.authenticationService.validateRefreshToken(refreshTokenString);
90
- sessionId = refreshToken.payload.sessionId;
90
+ sessionId = refreshToken.payload.session;
91
91
  }
92
92
  catch {
93
93
  throw error;
@@ -107,7 +107,7 @@ let AuthenticationApiController = class AuthenticationApiController {
107
107
  });
108
108
  }
109
109
  async changeSecret({ parameters, getAuditor }) {
110
- await this.authenticationService.changeSecret(parameters.subject, parameters.currentSecret, parameters.newSecret, await getAuditor());
110
+ await this.authenticationService.changeSecret({ tenantId: parameters.tenantId, subject: parameters.subject }, parameters.currentSecret, parameters.newSecret, await getAuditor());
111
111
  return 'ok';
112
112
  }
113
113
  /**
@@ -116,7 +116,7 @@ let AuthenticationApiController = class AuthenticationApiController {
116
116
  * @returns 'ok' if the secret reset was initialized.
117
117
  */
118
118
  async initSecretReset({ parameters, getAuditor }) {
119
- await this.authenticationService.initSecretReset(parameters.subject, parameters.data, await getAuditor());
119
+ await this.authenticationService.initSecretReset({ tenantId: parameters.tenantId, subject: parameters.subject }, parameters.data, await getAuditor());
120
120
  return 'ok';
121
121
  }
122
122
  /**
@@ -1,9 +1,11 @@
1
+ import type { SubjectInput } from '../types.js';
1
2
  export type AuthenticationAuditEvents = {
2
3
  'login-success': {
3
4
  sessionId: string;
4
5
  };
5
6
  'login-failure': {
6
- providedSubject: string;
7
+ subjectInput: SubjectInput;
8
+ subjectId: string | null;
7
9
  };
8
10
  'logout': {
9
11
  sessionId: string;
@@ -15,16 +17,16 @@ export type AuthenticationAuditEvents = {
15
17
  reason: string;
16
18
  };
17
19
  'impersonate-success': {
18
- impersonatedSubject: string;
20
+ impersonatedSubjectId: string;
19
21
  };
20
22
  'impersonate-failure': {
21
- impersonatedSubject: string;
22
- reason: string;
23
+ impersonatedSubjectId: string;
23
24
  };
24
25
  'unimpersonate-success': {};
25
26
  'change-secret-success': {};
26
27
  'change-secret-failure': {
27
- providedSubject: string;
28
+ subjectInput: SubjectInput;
29
+ subjectId: string | null;
28
30
  };
29
31
  'init-secret-reset': {};
30
32
  'reset-secret-success': {};