@xemahq/identity-client 0.3.2

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.
@@ -0,0 +1,474 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var IdentityBootstrapService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.IdentityBootstrapService = exports.IDENTITY_BOOTSTRAP_CONFIG = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const client_1 = require("../client");
19
+ const types_1 = require("../types");
20
+ exports.IDENTITY_BOOTSTRAP_CONFIG = Symbol('IDENTITY_BOOTSTRAP_CONFIG');
21
+ let IdentityBootstrapService = class IdentityBootstrapService {
22
+ static { IdentityBootstrapService_1 = this; }
23
+ config;
24
+ logger = new common_1.Logger(IdentityBootstrapService_1.name);
25
+ client;
26
+ clientId = null;
27
+ clientSecret = null;
28
+ tokenEndpoint = null;
29
+ keycloakBaseUrl = null;
30
+ allowedRealms = [];
31
+ primaryRealm = null;
32
+ registrationTokenScope = types_1.InternalTokenScope.ALL_REALMS_NAMESPACE;
33
+ accessToken = null;
34
+ tokenExpiresAt = 0;
35
+ tokenRefreshPromise = null;
36
+ lastCredentialFetchAt = 0;
37
+ static RECOVERY_DEBOUNCE_MS = 30_000;
38
+ static DISTRIBUTED_RECOVERY_DEBOUNCE_MS = 45_000;
39
+ userTokenCache = new Map();
40
+ userTokenInflight = new Map();
41
+ registrationStarted = false;
42
+ registrationAttempts = 0;
43
+ registrationTimer = null;
44
+ maxRegistrationAttempts;
45
+ baseRetryDelay;
46
+ maxRetryDelay;
47
+ readyResolve = null;
48
+ readyPromise;
49
+ isReady = false;
50
+ constructor(config) {
51
+ this.config = config;
52
+ this.client = new client_1.IdentityApiClient({
53
+ baseUrl: config.identityApiUrl,
54
+ internalToken: config.identityApiInternalToken,
55
+ });
56
+ this.maxRegistrationAttempts = config.maxRegistrationAttempts ?? Infinity;
57
+ this.baseRetryDelay = config.baseRetryDelay ?? 5000;
58
+ this.maxRetryDelay = config.maxRetryDelay ?? 300_000;
59
+ this.readyPromise = new Promise((resolve) => {
60
+ this.readyResolve = resolve;
61
+ });
62
+ }
63
+ async onModuleInit() {
64
+ if (this.config.clientId && this.config.clientSecret && this.config.tokenEndpoint) {
65
+ this.registrationStarted = true;
66
+ this.clientId = this.config.clientId;
67
+ this.clientSecret = this.config.clientSecret;
68
+ this.clientSecretWasSelfRegistered = false;
69
+ this.tokenEndpoint = this.config.tokenEndpoint;
70
+ this.keycloakBaseUrl = this.config.keycloakUrl ?? null;
71
+ this.allowedRealms = this.config.keycloakRealm ? [this.config.keycloakRealm] : [];
72
+ this.primaryRealm = this.config.keycloakRealm ?? null;
73
+ this.registrationTokenScope = types_1.InternalTokenScope.SINGLE_REALM;
74
+ try {
75
+ await this.refreshToken();
76
+ this.logger.log('Service account token obtained (pre-configured credentials)');
77
+ this.resolveReady(true);
78
+ return;
79
+ }
80
+ catch (error) {
81
+ const msg = error instanceof Error ? error.message : String(error);
82
+ throw new Error(`Pre-configured service account credentials are invalid: ${msg}. ` +
83
+ 'Fix clientId, clientSecret, and tokenEndpoint configuration.');
84
+ }
85
+ }
86
+ this.startBackgroundRegistration();
87
+ }
88
+ onModuleDestroy() {
89
+ if (this.registrationTimer) {
90
+ clearTimeout(this.registrationTimer);
91
+ this.registrationTimer = null;
92
+ }
93
+ }
94
+ async getAccessToken() {
95
+ if (this.accessToken && Date.now() < this.tokenExpiresAt - 30_000) {
96
+ return this.accessToken;
97
+ }
98
+ if (!this.clientId || !this.clientSecret || !this.tokenEndpoint) {
99
+ const ready = await this.waitForReady(30_000);
100
+ if (!ready || !this.clientId || !this.clientSecret || !this.tokenEndpoint) {
101
+ throw new Error('Service account credentials not available — identity-api registration may have failed');
102
+ }
103
+ }
104
+ if (this.tokenRefreshPromise) {
105
+ return this.tokenRefreshPromise;
106
+ }
107
+ this.tokenRefreshPromise = this.refreshToken();
108
+ try {
109
+ return await this.tokenRefreshPromise;
110
+ }
111
+ finally {
112
+ this.tokenRefreshPromise = null;
113
+ }
114
+ }
115
+ async getUserAccessToken(params) {
116
+ const realm = this.resolveUserTokenRealm(params.realm);
117
+ const cacheKey = `${realm}|${params.orgId}|${params.userId}|${params.audience ?? ''}`;
118
+ const cached = this.userTokenCache.get(cacheKey);
119
+ if (cached && Date.now() < cached.expiresAt - 30_000) {
120
+ return cached.token;
121
+ }
122
+ const inflight = this.userTokenInflight.get(cacheKey);
123
+ if (inflight) {
124
+ return inflight;
125
+ }
126
+ const promise = this.mintUserAccessToken(params, cacheKey, realm).finally(() => {
127
+ this.userTokenInflight.delete(cacheKey);
128
+ });
129
+ this.userTokenInflight.set(cacheKey, promise);
130
+ return promise;
131
+ }
132
+ async mintUserAccessToken(params, cacheKey, realm) {
133
+ if (!this.isReady) {
134
+ const ready = await this.waitForReady(30_000);
135
+ if (!ready) {
136
+ throw new Error('IdentityBootstrapService is not ready — cannot mint on-behalf-of token');
137
+ }
138
+ }
139
+ const request = {
140
+ userId: params.userId,
141
+ orgId: params.orgId,
142
+ realm: params.realm ?? realm,
143
+ };
144
+ if (params.audience !== undefined) {
145
+ request.audience = params.audience;
146
+ }
147
+ const response = await this.client.mintOnBehalfOfToken(request);
148
+ const expiresInMs = Math.max(response.expiresIn * 900, 30_000);
149
+ this.userTokenCache.set(cacheKey, {
150
+ token: response.accessToken,
151
+ expiresAt: Date.now() + expiresInMs,
152
+ });
153
+ return response.accessToken;
154
+ }
155
+ async waitForReady(timeoutMs = 60_000) {
156
+ if (this.isReady)
157
+ return true;
158
+ if (!this.registrationStarted) {
159
+ this.logger.warn('waitForReady called before onModuleInit — starting registration now');
160
+ this.startBackgroundRegistration();
161
+ }
162
+ return Promise.race([
163
+ this.readyPromise,
164
+ new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs)),
165
+ ]);
166
+ }
167
+ hasCredentials() {
168
+ return this.isReady && this.clientId !== null && this.clientSecret !== null;
169
+ }
170
+ getClientId() {
171
+ return this.clientId;
172
+ }
173
+ getKeycloakBaseUrl() {
174
+ return this.keycloakBaseUrl;
175
+ }
176
+ getAllowedRealms() {
177
+ return this.allowedRealms;
178
+ }
179
+ async isMember(orgId, userId, realm) {
180
+ if (!this.isReady) {
181
+ const ready = await this.waitForReady(30_000);
182
+ if (!ready) {
183
+ throw new Error('IdentityBootstrapService is not ready — cannot verify membership');
184
+ }
185
+ }
186
+ const resolvedRealm = realm ?? this.resolveUserTokenRealm();
187
+ const response = await this.client.verifyMembership(userId, orgId, resolvedRealm);
188
+ return response.isMember;
189
+ }
190
+ async listOrgIds() {
191
+ if (!this.isReady) {
192
+ const ready = await this.waitForReady(30_000);
193
+ if (!ready) {
194
+ throw new Error('Identity bootstrap not ready after 30s — cannot list org IDs');
195
+ }
196
+ }
197
+ if (!this.allowedRealms.length) {
198
+ throw new Error('No allowed realms available — service registration may have failed');
199
+ }
200
+ const allIds = new Set();
201
+ for (const realm of this.allowedRealms) {
202
+ const ids = await this.client.listOrgIds(realm);
203
+ for (const id of ids) {
204
+ allIds.add(id);
205
+ }
206
+ }
207
+ return [...allIds];
208
+ }
209
+ startBackgroundRegistration() {
210
+ if (this.registrationStarted)
211
+ return;
212
+ this.registrationStarted = true;
213
+ this.logger.log({
214
+ message: 'Starting background identity-api registration',
215
+ serviceName: this.config.serviceName,
216
+ });
217
+ this.attemptRegistration();
218
+ }
219
+ async attemptRegistration() {
220
+ if (this.isReady)
221
+ return;
222
+ try {
223
+ const response = await this.client.registerServiceFull({
224
+ name: this.config.serviceName,
225
+ displayName: this.config.serviceDisplayName,
226
+ description: this.config.serviceDescription,
227
+ serviceType: 'BACKEND',
228
+ regenerateSecret: false,
229
+ ...(this.config.keycloakRealm ? { realm: this.config.keycloakRealm } : {}),
230
+ });
231
+ this.clientId = response.id;
232
+ this.tokenEndpoint = response.tokenEndpoint;
233
+ const registrationMetadata = this.requireRegistrationMetadata(response.keycloakBaseUrl, response.allowedRealms, response.primaryRealm, response.internalTokenScope);
234
+ this.keycloakBaseUrl = registrationMetadata.keycloakBaseUrl;
235
+ this.allowedRealms = registrationMetadata.allowedRealms;
236
+ this.primaryRealm = registrationMetadata.primaryRealm;
237
+ this.registrationTokenScope = registrationMetadata.internalTokenScope;
238
+ if (!response.clientSecret) {
239
+ throw new Error(`identity-api registration response missing required clientSecret ` +
240
+ `(alreadyExisted=${response.alreadyExisted}). Server is on an ` +
241
+ `older version that does not return existing secrets idempotently.`);
242
+ }
243
+ this.clientSecret = response.clientSecret;
244
+ this.clientSecretWasSelfRegistered = true;
245
+ await this.refreshToken();
246
+ this.logger.log({
247
+ message: 'Identity-api registration successful',
248
+ serviceName: this.config.serviceName,
249
+ clientId: this.clientId,
250
+ attempts: this.registrationAttempts + 1,
251
+ });
252
+ this.registrationAttempts = 0;
253
+ this.lastCredentialFetchAt = Date.now();
254
+ this.resolveReady(true);
255
+ }
256
+ catch (error) {
257
+ this.scheduleRetry(error);
258
+ }
259
+ }
260
+ requireRegistrationMetadata(keycloakBaseUrl, allowedRealms, primaryRealm, internalTokenScope) {
261
+ if (!keycloakBaseUrl) {
262
+ throw new Error('identity-api registration response missing required field: keycloakBaseUrl');
263
+ }
264
+ if (!allowedRealms || allowedRealms.length === 0) {
265
+ throw new Error('identity-api registration response missing required field: allowedRealms');
266
+ }
267
+ return {
268
+ keycloakBaseUrl,
269
+ allowedRealms,
270
+ primaryRealm: primaryRealm ?? null,
271
+ internalTokenScope: internalTokenScope ?? types_1.InternalTokenScope.ALL_REALMS_NAMESPACE,
272
+ };
273
+ }
274
+ resolveUserTokenRealm(explicitRealm) {
275
+ if (explicitRealm) {
276
+ return explicitRealm;
277
+ }
278
+ if (this.registrationTokenScope === types_1.InternalTokenScope.SINGLE_REALM) {
279
+ if (!this.primaryRealm) {
280
+ throw new Error('Identity registration indicates SINGLE_REALM scope but no primary realm is available');
281
+ }
282
+ return this.primaryRealm;
283
+ }
284
+ throw new Error(`Realm is required for on-behalf-of token mint when token scope is ${this.registrationTokenScope}`);
285
+ }
286
+ scheduleRetry(error) {
287
+ this.registrationAttempts++;
288
+ const errorMessage = error instanceof client_1.IdentityApiError
289
+ ? `${error.message} (status: ${error.statusCode})`
290
+ : error instanceof Error
291
+ ? error.message
292
+ : String(error);
293
+ if (this.registrationAttempts >= this.maxRegistrationAttempts) {
294
+ this.logger.error({
295
+ message: 'Identity-api registration failed — max attempts reached',
296
+ attempts: this.registrationAttempts,
297
+ error: errorMessage,
298
+ });
299
+ this.resolveReady(false);
300
+ return;
301
+ }
302
+ const delay = Math.min(this.baseRetryDelay * Math.pow(2, this.registrationAttempts - 1), this.maxRetryDelay);
303
+ this.logger.warn({
304
+ message: 'Identity-api registration failed, will retry',
305
+ attempt: this.registrationAttempts,
306
+ nextRetryInSeconds: Math.round(delay / 1000),
307
+ error: errorMessage,
308
+ });
309
+ this.registrationTimer = setTimeout(() => {
310
+ this.attemptRegistration();
311
+ }, delay);
312
+ }
313
+ clientSecretWasSelfRegistered = false;
314
+ async refreshToken() {
315
+ return this.refreshTokenWithRecovery(false);
316
+ }
317
+ async refreshTokenWithRecovery(recoveryAttempted) {
318
+ if (!this.clientId || !this.clientSecret || !this.tokenEndpoint) {
319
+ throw new Error('Cannot refresh token — credentials not available');
320
+ }
321
+ const response = await fetch(this.tokenEndpoint, {
322
+ method: 'POST',
323
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
324
+ body: new URLSearchParams({
325
+ grant_type: 'client_credentials',
326
+ client_id: this.clientId,
327
+ client_secret: this.clientSecret,
328
+ }).toString(),
329
+ });
330
+ if (response.status === 401 && !recoveryAttempted && this.clientSecretWasSelfRegistered) {
331
+ const text = await response.text().catch(() => '');
332
+ const sinceLastLocalFetch = Date.now() - this.lastCredentialFetchAt;
333
+ if (sinceLastLocalFetch < IdentityBootstrapService_1.RECOVERY_DEBOUNCE_MS) {
334
+ throw new Error(`Token request failed: 401 ${response.statusText} — credentials ` +
335
+ `were just refreshed ${sinceLastLocalFetch}ms ago; not refetching to ` +
336
+ `avoid storm. Server response: ${text.slice(0, 300)}`);
337
+ }
338
+ try {
339
+ const serverState = await this.checkCredentialRecoveryState();
340
+ if (serverState && serverState.shouldSkipRecovery) {
341
+ throw new Error(`Token request failed: 401 ${response.statusText} — another replica ` +
342
+ `fetched credentials ${serverState.timeSinceLastRecovery}ms ago; ` +
343
+ `waiting for ${serverState.waitTimeMs}ms before retrying. ` +
344
+ `Server response: ${text.slice(0, 300)}`);
345
+ }
346
+ }
347
+ catch (stateCheckError) {
348
+ if (stateCheckError instanceof Error && stateCheckError.message.includes('should skip')) {
349
+ throw stateCheckError;
350
+ }
351
+ this.logger.warn({
352
+ message: 'Failed to check distributed recovery state, proceeding with local coordination',
353
+ error: stateCheckError instanceof Error ? stateCheckError.message : String(stateCheckError),
354
+ });
355
+ }
356
+ this.logger.warn({
357
+ message: 'Token request returned 401 — Keycloak client secret was rotated ' +
358
+ 'out of band; fetching current secret from identity-api',
359
+ clientId: this.clientId,
360
+ responseBody: text.slice(0, 300),
361
+ });
362
+ this.accessToken = null;
363
+ this.tokenExpiresAt = 0;
364
+ await this.fetchCurrentCredentials();
365
+ return this.refreshTokenWithRecovery(true);
366
+ }
367
+ if (!response.ok) {
368
+ const text = await response.text().catch(() => '');
369
+ throw new Error(`Token request failed: ${response.status} ${response.statusText} — ${text}`);
370
+ }
371
+ const data = (await response.json());
372
+ this.accessToken = data.access_token;
373
+ const expiresIn = data.expires_in || 60;
374
+ const jitterFraction = 0.8 + Math.random() * 0.15;
375
+ this.tokenExpiresAt = Date.now() + expiresIn * 1000 * jitterFraction;
376
+ return this.accessToken;
377
+ }
378
+ async fetchCurrentCredentials() {
379
+ const response = await this.client.registerServiceFull({
380
+ name: this.config.serviceName,
381
+ displayName: this.config.serviceDisplayName,
382
+ description: this.config.serviceDescription,
383
+ serviceType: 'BACKEND',
384
+ regenerateSecret: false,
385
+ ...(this.config.keycloakRealm ? { realm: this.config.keycloakRealm } : {}),
386
+ });
387
+ if (!response.clientSecret) {
388
+ throw new Error('identity-api did not return clientSecret on idempotent re-register ' +
389
+ '— server is on an older version that does not echo existing secrets');
390
+ }
391
+ this.clientId = response.id;
392
+ this.clientSecret = response.clientSecret;
393
+ this.tokenEndpoint = response.tokenEndpoint;
394
+ const metadata = this.requireRegistrationMetadata(response.keycloakBaseUrl, response.allowedRealms, response.primaryRealm, response.internalTokenScope);
395
+ this.keycloakBaseUrl = metadata.keycloakBaseUrl;
396
+ this.allowedRealms = metadata.allowedRealms;
397
+ this.primaryRealm = metadata.primaryRealm;
398
+ this.registrationTokenScope = metadata.internalTokenScope;
399
+ this.lastCredentialFetchAt = Date.now();
400
+ try {
401
+ await this.recordCredentialRecovery();
402
+ }
403
+ catch (error) {
404
+ this.logger.warn({
405
+ message: 'Failed to record credential recovery in distributed state',
406
+ error: error instanceof Error ? error.message : String(error),
407
+ });
408
+ }
409
+ }
410
+ async checkCredentialRecoveryState() {
411
+ try {
412
+ const response = await fetch(`${this.config.identityApiUrl}/internal/services/recovery-state/${encodeURIComponent(this.config.serviceName)}`, {
413
+ method: 'GET',
414
+ headers: {
415
+ 'Authorization': `Bearer ${this.config.identityApiInternalToken}`,
416
+ },
417
+ });
418
+ if (!response.ok) {
419
+ if (response.status === 404) {
420
+ return null;
421
+ }
422
+ return null;
423
+ }
424
+ const data = (await response.json());
425
+ return data;
426
+ }
427
+ catch (error) {
428
+ this.logger.debug({
429
+ message: 'Failed to check distributed recovery state (network error)',
430
+ error: error instanceof Error ? error.message : String(error),
431
+ });
432
+ return null;
433
+ }
434
+ }
435
+ async recordCredentialRecovery() {
436
+ try {
437
+ const response = await fetch(`${this.config.identityApiUrl}/internal/services/record-recovery/${encodeURIComponent(this.config.serviceName)}`, {
438
+ method: 'POST',
439
+ headers: {
440
+ 'Authorization': `Bearer ${this.config.identityApiInternalToken}`,
441
+ 'Content-Type': 'application/json',
442
+ },
443
+ body: JSON.stringify({}),
444
+ });
445
+ if (!response.ok) {
446
+ this.logger.warn({
447
+ message: 'Failed to record credential recovery on server',
448
+ status: response.status,
449
+ statusText: response.statusText,
450
+ });
451
+ }
452
+ }
453
+ catch (error) {
454
+ this.logger.debug({
455
+ message: 'Failed to record credential recovery (network error)',
456
+ error: error instanceof Error ? error.message : String(error),
457
+ });
458
+ }
459
+ }
460
+ resolveReady(success) {
461
+ this.isReady = success;
462
+ if (this.readyResolve) {
463
+ this.readyResolve(success);
464
+ this.readyResolve = null;
465
+ }
466
+ }
467
+ };
468
+ exports.IdentityBootstrapService = IdentityBootstrapService;
469
+ exports.IdentityBootstrapService = IdentityBootstrapService = IdentityBootstrapService_1 = __decorate([
470
+ (0, common_1.Injectable)(),
471
+ __param(0, (0, common_1.Inject)(exports.IDENTITY_BOOTSTRAP_CONFIG)),
472
+ __metadata("design:paramtypes", [Object])
473
+ ], IdentityBootstrapService);
474
+ //# sourceMappingURL=identity-bootstrap.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-bootstrap.service.js","sourceRoot":"","sources":["../../src/nestjs/identity-bootstrap.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { IdentityBootstrapModule, IdentityBootstrapModuleAsyncOptions, } from './identity-bootstrap.module';
2
+ export { IdentityBootstrapService, IdentityBootstrapConfig, IDENTITY_BOOTSTRAP_CONFIG, } from './identity-bootstrap.service';
3
+ export { OrgAuthModule, OrgAdminGuard, ORG_AUTH_CONFIG, type OrgAuthConfig, type OrgAuthModuleAsyncOptions, } from './org-auth';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ORG_AUTH_CONFIG = exports.OrgAdminGuard = exports.OrgAuthModule = exports.IDENTITY_BOOTSTRAP_CONFIG = exports.IdentityBootstrapService = exports.IdentityBootstrapModule = void 0;
4
+ var identity_bootstrap_module_1 = require("./identity-bootstrap.module");
5
+ Object.defineProperty(exports, "IdentityBootstrapModule", { enumerable: true, get: function () { return identity_bootstrap_module_1.IdentityBootstrapModule; } });
6
+ var identity_bootstrap_service_1 = require("./identity-bootstrap.service");
7
+ Object.defineProperty(exports, "IdentityBootstrapService", { enumerable: true, get: function () { return identity_bootstrap_service_1.IdentityBootstrapService; } });
8
+ Object.defineProperty(exports, "IDENTITY_BOOTSTRAP_CONFIG", { enumerable: true, get: function () { return identity_bootstrap_service_1.IDENTITY_BOOTSTRAP_CONFIG; } });
9
+ var org_auth_1 = require("./org-auth");
10
+ Object.defineProperty(exports, "OrgAuthModule", { enumerable: true, get: function () { return org_auth_1.OrgAuthModule; } });
11
+ Object.defineProperty(exports, "OrgAdminGuard", { enumerable: true, get: function () { return org_auth_1.OrgAdminGuard; } });
12
+ Object.defineProperty(exports, "ORG_AUTH_CONFIG", { enumerable: true, get: function () { return org_auth_1.ORG_AUTH_CONFIG; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":";;;AAAA,yEAGqC;AAFnC,oIAAA,uBAAuB,OAAA;AAGzB,2EAIsC;AAHpC,sIAAA,wBAAwB,OAAA;AAExB,uIAAA,yBAAyB,OAAA;AAE3B,uCAMoB;AALlB,yGAAA,aAAa,OAAA;AACb,yGAAA,aAAa,OAAA;AACb,2GAAA,eAAe,OAAA"}
@@ -0,0 +1,3 @@
1
+ export { OrgAuthModule } from './org-auth.module';
2
+ export { OrgAdminGuard } from './org-admin.guard';
3
+ export { ORG_AUTH_CONFIG, type OrgAuthConfig, type OrgAuthModuleAsyncOptions, } from './org-auth.types';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ORG_AUTH_CONFIG = exports.OrgAdminGuard = exports.OrgAuthModule = void 0;
4
+ var org_auth_module_1 = require("./org-auth.module");
5
+ Object.defineProperty(exports, "OrgAuthModule", { enumerable: true, get: function () { return org_auth_module_1.OrgAuthModule; } });
6
+ var org_admin_guard_1 = require("./org-admin.guard");
7
+ Object.defineProperty(exports, "OrgAdminGuard", { enumerable: true, get: function () { return org_admin_guard_1.OrgAdminGuard; } });
8
+ var org_auth_types_1 = require("./org-auth.types");
9
+ Object.defineProperty(exports, "ORG_AUTH_CONFIG", { enumerable: true, get: function () { return org_auth_types_1.ORG_AUTH_CONFIG; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/nestjs/org-auth/index.ts"],"names":[],"mappings":";;;AAAA,qDAAkD;AAAzC,gHAAA,aAAa,OAAA;AACtB,qDAAkD;AAAzC,gHAAA,aAAa,OAAA;AACtB,mDAI0B;AAHxB,iHAAA,eAAe,OAAA"}
@@ -0,0 +1,13 @@
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ import type { OrgAuthConfig } from './org-auth.types';
3
+ export declare class OrgAdminGuard implements CanActivate {
4
+ private readonly logger;
5
+ private readonly identityClient;
6
+ private readonly cacheTtlMs;
7
+ private readonly cache;
8
+ constructor(config: OrgAuthConfig);
9
+ canActivate(context: ExecutionContext): Promise<boolean>;
10
+ private resolveOrgRole;
11
+ private extractContext;
12
+ private evictExpiredEntries;
13
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var OrgAdminGuard_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.OrgAdminGuard = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const client_1 = require("../../client");
19
+ const types_1 = require("../../types");
20
+ const org_auth_types_1 = require("./org-auth.types");
21
+ const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
22
+ const MAX_CACHE_SIZE = 10_000;
23
+ let OrgAdminGuard = OrgAdminGuard_1 = class OrgAdminGuard {
24
+ logger = new common_1.Logger(OrgAdminGuard_1.name);
25
+ identityClient;
26
+ cacheTtlMs;
27
+ cache = new Map();
28
+ constructor(config) {
29
+ this.identityClient = new client_1.IdentityApiClient({
30
+ baseUrl: config.identityApiUrl,
31
+ internalToken: config.identityApiInternalToken,
32
+ });
33
+ this.cacheTtlMs = config.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
34
+ }
35
+ async canActivate(context) {
36
+ const request = context.switchToHttp().getRequest();
37
+ const ctx = this.extractContext(request);
38
+ if (!ctx) {
39
+ throw new common_1.ForbiddenException('Request context not available');
40
+ }
41
+ if (ctx.roles.includes('platform_admin')) {
42
+ return true;
43
+ }
44
+ const { orgId, actorId } = ctx;
45
+ if (!orgId || !actorId) {
46
+ throw new common_1.ForbiddenException('Organization context required');
47
+ }
48
+ const role = await this.resolveOrgRole(orgId, actorId, ctx.realmId);
49
+ if (!role || !types_1.ORG_ADMIN_ROLES.has(role)) {
50
+ this.logger.warn(`Org admin access denied for actor ${actorId} in org ${orgId} (role: ${role ?? 'none'})`);
51
+ throw new common_1.ForbiddenException('Organization administrator privileges required');
52
+ }
53
+ return true;
54
+ }
55
+ async resolveOrgRole(orgId, actorId, realm) {
56
+ const cacheKey = `${orgId}:${actorId}`;
57
+ const cached = this.cache.get(cacheKey);
58
+ if (cached && cached.expiresAt > Date.now()) {
59
+ return cached.response.role;
60
+ }
61
+ try {
62
+ const response = await this.identityClient.verifyMembership(actorId, orgId, realm);
63
+ this.cache.set(cacheKey, {
64
+ response,
65
+ expiresAt: Date.now() + this.cacheTtlMs,
66
+ });
67
+ if (this.cache.size > MAX_CACHE_SIZE) {
68
+ this.evictExpiredEntries();
69
+ }
70
+ return response.role;
71
+ }
72
+ catch (error) {
73
+ const message = error instanceof Error ? error.message : 'Unknown error';
74
+ this.logger.error(`Failed to verify org membership for actor ${actorId} in org ${orgId}: ${message}`);
75
+ throw new common_1.ServiceUnavailableException('Unable to verify organization membership. Please try again.');
76
+ }
77
+ }
78
+ extractContext(request) {
79
+ const symbols = Object.getOwnPropertySymbols(request);
80
+ for (const sym of symbols) {
81
+ if (sym.description === 'REQUEST_CONTEXT') {
82
+ const ctx = request[sym];
83
+ return ctx;
84
+ }
85
+ }
86
+ return undefined;
87
+ }
88
+ evictExpiredEntries() {
89
+ const now = Date.now();
90
+ for (const [key, entry] of this.cache) {
91
+ if (entry.expiresAt <= now) {
92
+ this.cache.delete(key);
93
+ }
94
+ }
95
+ }
96
+ };
97
+ exports.OrgAdminGuard = OrgAdminGuard;
98
+ exports.OrgAdminGuard = OrgAdminGuard = OrgAdminGuard_1 = __decorate([
99
+ (0, common_1.Injectable)(),
100
+ __param(0, (0, common_1.Inject)(org_auth_types_1.ORG_AUTH_CONFIG)),
101
+ __metadata("design:paramtypes", [Object])
102
+ ], OrgAdminGuard);
103
+ //# sourceMappingURL=org-admin.guard.js.map