@flusys/nestjs-auth 0.1.0-beta.3 → 1.0.0-rc

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 (102) hide show
  1. package/README.md +274 -301
  2. package/cjs/config/auth.constants.js +22 -4
  3. package/cjs/controllers/authentication.controller.js +222 -38
  4. package/cjs/controllers/branch.controller.js +46 -4
  5. package/cjs/controllers/company-selection.controller.js +27 -20
  6. package/cjs/controllers/company.controller.js +46 -4
  7. package/cjs/controllers/user-permission.controller.js +40 -37
  8. package/cjs/controllers/user.controller.js +222 -23
  9. package/cjs/dtos/authentication.dto.js +119 -13
  10. package/cjs/dtos/user-permission.dto.js +28 -0
  11. package/cjs/dtos/user.dto.js +19 -4
  12. package/cjs/entities/index.js +5 -1
  13. package/cjs/entities/pending-registration.entity.js +125 -0
  14. package/cjs/entities/user-company-permission.entity.js +0 -6
  15. package/cjs/entities/user-token.entity.js +129 -0
  16. package/cjs/guards/auth-throttler.guard.js +53 -0
  17. package/cjs/interceptors/clear-token.interceptor.js +3 -6
  18. package/cjs/interceptors/set-token.interceptor.js +38 -31
  19. package/cjs/interfaces/auth-email-provider.interface.js +45 -0
  20. package/cjs/interfaces/authentication.interface.js +0 -3
  21. package/cjs/interfaces/index.js +2 -0
  22. package/cjs/interfaces/user-enricher.interface.js +4 -0
  23. package/cjs/modules/auth.module.js +8 -20
  24. package/cjs/services/auth-config.service.js +42 -47
  25. package/cjs/services/auth-datasource.provider.js +18 -34
  26. package/cjs/services/auth-email.service.js +471 -0
  27. package/cjs/services/authentication.service.js +240 -153
  28. package/cjs/services/branch.service.js +15 -48
  29. package/cjs/services/company-selection-session.service.js +1 -1
  30. package/cjs/services/company.service.js +7 -36
  31. package/cjs/services/index.js +1 -0
  32. package/cjs/services/user-permission.service.js +9 -29
  33. package/cjs/services/user.service.js +228 -107
  34. package/cjs/strategies/jwt.strategy.js +14 -1
  35. package/cjs/validators/password.validator.js +45 -0
  36. package/config/auth.constants.d.ts +5 -0
  37. package/controllers/authentication.controller.d.ts +13 -9
  38. package/controllers/company-selection.controller.d.ts +6 -2
  39. package/controllers/user.controller.d.ts +33 -0
  40. package/dtos/authentication.dto.d.ts +21 -3
  41. package/dtos/company-branch.dto.d.ts +0 -1
  42. package/dtos/company.dto.d.ts +0 -1
  43. package/dtos/user-permission.dto.d.ts +4 -0
  44. package/dtos/user.dto.d.ts +1 -2
  45. package/entities/index.d.ts +7 -3
  46. package/entities/pending-registration.entity.d.ts +17 -0
  47. package/entities/user-company-permission.entity.d.ts +0 -2
  48. package/entities/user-token.entity.d.ts +15 -0
  49. package/fesm/config/auth.constants.js +11 -8
  50. package/fesm/controllers/authentication.controller.js +224 -40
  51. package/fesm/controllers/branch.controller.js +49 -7
  52. package/fesm/controllers/company-selection.controller.js +28 -21
  53. package/fesm/controllers/company.controller.js +49 -7
  54. package/fesm/controllers/user-permission.controller.js +41 -38
  55. package/fesm/controllers/user.controller.js +225 -26
  56. package/fesm/dtos/authentication.dto.js +123 -111
  57. package/fesm/dtos/user-permission.dto.js +28 -0
  58. package/fesm/dtos/user.dto.js +20 -5
  59. package/fesm/entities/index.js +7 -1
  60. package/fesm/entities/pending-registration.entity.js +115 -0
  61. package/fesm/entities/user-company-permission.entity.js +0 -6
  62. package/fesm/entities/user-token.entity.js +113 -0
  63. package/fesm/guards/auth-throttler.guard.js +43 -0
  64. package/fesm/interceptors/clear-token.interceptor.js +2 -5
  65. package/fesm/interceptors/set-token.interceptor.js +37 -30
  66. package/fesm/interfaces/auth-email-provider.interface.js +38 -0
  67. package/fesm/interfaces/authentication.interface.js +1 -7
  68. package/fesm/interfaces/index.js +2 -0
  69. package/fesm/interfaces/user-enricher.interface.js +26 -0
  70. package/fesm/modules/auth.module.js +10 -22
  71. package/fesm/services/auth-config.service.js +42 -47
  72. package/fesm/services/auth-datasource.provider.js +19 -35
  73. package/fesm/services/auth-email.service.js +420 -0
  74. package/fesm/services/authentication.service.js +238 -151
  75. package/fesm/services/branch.service.js +16 -49
  76. package/fesm/services/company-selection-session.service.js +1 -1
  77. package/fesm/services/company.service.js +8 -37
  78. package/fesm/services/index.js +1 -0
  79. package/fesm/services/user-permission.service.js +10 -30
  80. package/fesm/services/user.service.js +229 -108
  81. package/fesm/strategies/jwt.strategy.js +14 -1
  82. package/fesm/validators/password.validator.js +48 -0
  83. package/guards/auth-throttler.guard.d.ts +7 -0
  84. package/interceptors/set-token.interceptor.d.ts +1 -0
  85. package/interfaces/auth-email-provider.interface.d.ts +6 -0
  86. package/interfaces/auth-module-options.interface.d.ts +4 -1
  87. package/interfaces/authentication.interface.d.ts +14 -0
  88. package/interfaces/index.d.ts +2 -0
  89. package/interfaces/user-enricher.interface.d.ts +64 -0
  90. package/interfaces/user.interface.d.ts +1 -0
  91. package/modules/auth.module.d.ts +0 -1
  92. package/package.json +4 -4
  93. package/services/auth-config.service.d.ts +5 -1
  94. package/services/auth-email.service.d.ts +51 -0
  95. package/services/authentication.service.d.ts +21 -12
  96. package/services/branch.service.d.ts +2 -5
  97. package/services/company-selection-session.service.d.ts +1 -1
  98. package/services/company.service.d.ts +1 -4
  99. package/services/index.d.ts +1 -0
  100. package/services/user-permission.service.d.ts +0 -1
  101. package/services/user.service.d.ts +20 -6
  102. package/validators/password.validator.d.ts +10 -0
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "ClearToken", {
10
10
  });
11
11
  const _common = require("@nestjs/common");
12
12
  const _rxjs = require("rxjs");
13
+ const _config = require("../config");
13
14
  const _authconfigservice = require("../services/auth-config.service");
14
15
  function _define_property(obj, key, value) {
15
16
  if (key in obj) {
@@ -38,23 +39,19 @@ function _ts_param(paramIndex, decorator) {
38
39
  decorator(target, key, paramIndex);
39
40
  };
40
41
  }
41
- const DEFAULT_COOKIE_NAME = 'fsn_refresh_token';
42
42
  let ClearToken = class ClearToken {
43
43
  get cookieName() {
44
- return this.authConfig?.getRefreshTokenCookieName() ?? DEFAULT_COOKIE_NAME;
44
+ return this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
45
45
  }
46
46
  intercept(context, next) {
47
47
  const req = context.switchToHttp().getRequest();
48
48
  const res = context.switchToHttp().getResponse();
49
49
  return next.handle().pipe((0, _rxjs.map)((value)=>{
50
- // Clear the refresh token cookie
51
50
  this.clearRefreshTokenCookie(req, res);
52
51
  return value;
53
52
  }));
54
53
  }
55
- /**
56
- * Clear refresh token cookie
57
- */ clearRefreshTokenCookie(req, res) {
54
+ clearRefreshTokenCookie(req, res) {
58
55
  const origin = req.headers.origin || '';
59
56
  const hostname = req.hostname || '';
60
57
  const isHttps = origin.startsWith('https://') || req.secure;
@@ -11,6 +11,7 @@ Object.defineProperty(exports, "SetToken", {
11
11
  const _common = require("@nestjs/common");
12
12
  const _buffer = require("buffer");
13
13
  const _rxjs = require("rxjs");
14
+ const _config = require("../config");
14
15
  const _authconfigservice = require("../services/auth-config.service");
15
16
  function _define_property(obj, key, value) {
16
17
  if (key in obj) {
@@ -39,80 +40,85 @@ function _ts_param(paramIndex, decorator) {
39
40
  decorator(target, key, paramIndex);
40
41
  };
41
42
  }
42
- const DEFAULT_COOKIE_NAME = 'fsn_refresh_token';
43
- const MAX_COOKIE_BYTES = 3500;
44
43
  let SetToken = class SetToken {
45
44
  get cookieName() {
46
- return this.authConfig?.getRefreshTokenCookieName() ?? DEFAULT_COOKIE_NAME;
45
+ return this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
46
+ }
47
+ /** Convert expiration string (e.g., '7d', '24h') to milliseconds */ getMaxAgeMs() {
48
+ const expiry = this.authConfig?.getRefreshTokenExpiration() ?? '7d';
49
+ const match = expiry.match(/^(\d+)(s|m|h|d|w)$/);
50
+ if (!match) {
51
+ return 7 * 24 * 60 * 60 * 1000; // Default 7 days
52
+ }
53
+ const value = parseInt(match[1], 10);
54
+ const unit = match[2];
55
+ const multipliers = {
56
+ s: 1000,
57
+ m: 60 * 1000,
58
+ h: 60 * 60 * 1000,
59
+ d: 24 * 60 * 60 * 1000,
60
+ w: 7 * 24 * 60 * 60 * 1000
61
+ };
62
+ return value * (multipliers[unit] || multipliers['d']);
47
63
  }
48
64
  intercept(context, next) {
49
65
  const req = context.switchToHttp().getRequest();
50
66
  const res = context.switchToHttp().getResponse();
51
67
  return next.handle().pipe((0, _rxjs.map)((value)=>{
52
- // Skip if no refreshToken in response
53
68
  if (!value || !value.refreshToken) {
54
69
  return value;
55
70
  }
56
71
  const isBrowser = this.isBrowserRequest(req);
57
72
  const tokenValue = value.refreshToken;
58
73
  if (isBrowser) {
59
- // Browser: Set cookie and remove from response body
60
74
  this.setRefreshTokenCookie(req, res, tokenValue);
61
- // Return response without refreshToken for browsers
62
75
  const { refreshToken, ...responseWithoutToken } = value;
63
76
  return responseWithoutToken;
64
77
  }
65
- // API/Mobile: Keep refreshToken in response body
66
78
  return value;
67
79
  }), (0, _rxjs.catchError)((err)=>(0, _rxjs.throwError)(()=>err)));
68
80
  }
69
- /**
70
- * Detect if request is from a browser
71
- * Checks Accept header and custom X-Client-Type header
72
- */ isBrowserRequest(req) {
73
- // Check custom header first (allows explicit client identification)
81
+ isBrowserRequest(req) {
74
82
  const clientType = req.headers['x-client-type'];
75
83
  if (clientType) {
76
84
  return clientType.toLowerCase() === 'browser' || clientType.toLowerCase() === 'web';
77
85
  }
78
- // Check Accept header - browsers typically include text/html
79
86
  const accept = req.headers['accept'] || '';
80
87
  if (accept.includes('text/html')) {
81
88
  return true;
82
89
  }
83
- // Check User-Agent for common browsers
84
90
  const userAgent = req.headers['user-agent'] || '';
85
91
  const browserPatterns = /mozilla|chrome|safari|firefox|edge|opera|msie/i;
86
- if (browserPatterns.test(userAgent) && !userAgent.includes('Postman')) {
87
- return true;
88
- }
89
- return false;
92
+ return browserPatterns.test(userAgent) && !userAgent.includes('Postman');
90
93
  }
91
- /**
92
- * Set refresh token in HTTP-only cookie
93
- */ setRefreshTokenCookie(req, res, tokenValue) {
94
- const origin = req.headers.origin || '';
94
+ setRefreshTokenCookie(req, res, tokenValue) {
95
95
  const hostname = req.hostname || '';
96
- const isHttps = origin.startsWith('https://') || req.secure;
97
- let cookieDomain = hostname;
96
+ // Determine if we're in production - always use secure cookies in production
97
+ // This handles TLS-terminating proxies correctly (they set x-forwarded-proto)
98
+ const isProduction = process.env.NODE_ENV === 'production';
99
+ const forwardedProto = req.headers['x-forwarded-proto'];
100
+ const isHttps = isProduction || forwardedProto === 'https' || req.secure;
101
+ // Set cookie domain - only for subdomains with 3+ parts
102
+ // For security, limit to same domain unless explicitly configured
103
+ let cookieDomain;
98
104
  const domainParts = hostname.split('.');
99
- if (domainParts.length > 2) {
105
+ if (domainParts.length > 2 && !hostname.includes('localhost')) {
100
106
  cookieDomain = '.' + domainParts.slice(-2).join('.');
101
107
  }
102
- // Check cookie size
103
- const rawCookieString = `${this.cookieName}=${tokenValue}; HttpOnly; Domain=${cookieDomain}`;
108
+ const rawCookieString = `${this.cookieName}=${tokenValue}; HttpOnly`;
104
109
  const estimatedBytes = _buffer.Buffer.byteLength(rawCookieString, 'utf8');
105
- if (estimatedBytes > MAX_COOKIE_BYTES) {
110
+ if (estimatedBytes > _config.MAX_COOKIE_BYTES) {
106
111
  throw new _common.PayloadTooLargeException(`Refresh token too large (≈${estimatedBytes} bytes)`);
107
112
  }
108
- // Set HTTP-only secure cookie
109
113
  res.cookie(this.cookieName, tokenValue, {
110
114
  httpOnly: true,
111
115
  secure: isHttps,
112
116
  sameSite: isHttps ? 'strict' : 'lax',
113
- domain: cookieDomain,
117
+ ...cookieDomain && {
118
+ domain: cookieDomain
119
+ },
114
120
  path: '/',
115
- maxAge: 7 * 24 * 60 * 60 * 1000
121
+ maxAge: this.getMaxAgeMs()
116
122
  });
117
123
  }
118
124
  constructor(authConfig){
@@ -123,6 +129,7 @@ let SetToken = class SetToken {
123
129
  SetToken = _ts_decorate([
124
130
  (0, _common.Injectable)(),
125
131
  _ts_param(0, (0, _common.Optional)()),
132
+ _ts_param(0, (0, _common.Inject)(_authconfigservice.AuthConfigService)),
126
133
  _ts_metadata("design:type", Function),
127
134
  _ts_metadata("design:paramtypes", [
128
135
  typeof _authconfigservice.AuthConfigService === "undefined" ? Object : _authconfigservice.AuthConfigService
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Auth Email Provider Interface
3
+ *
4
+ * This interface defines the contract for email sending in the auth module.
5
+ * It allows auth to work independently of the email module.
6
+ *
7
+ * To use email features in auth:
8
+ * 1. Provide AUTH_EMAIL_PROVIDER in your app module
9
+ * 2. Implement IAuthEmailProvider using EmailSendService from nestjs-email
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * // In app.module.ts or a provider file
14
+ * {
15
+ * provide: AUTH_EMAIL_PROVIDER,
16
+ * useFactory: (emailSendService: EmailSendService) => ({
17
+ * sendPasswordResetEmail: async (email, token, resetUrl) => {
18
+ * await emailSendService.sendTemplateEmail({
19
+ * templateSlug: 'password-reset',
20
+ * to: email,
21
+ * variables: { resetUrl, token },
22
+ * });
23
+ * },
24
+ * sendVerificationEmail: async (email, token, verifyUrl) => {
25
+ * await emailSendService.sendTemplateEmail({
26
+ * templateSlug: 'email-verification',
27
+ * to: email,
28
+ * variables: { verifyUrl, token },
29
+ * });
30
+ * },
31
+ * }),
32
+ * inject: [EmailSendService],
33
+ * }
34
+ * ```
35
+ */ "use strict";
36
+ Object.defineProperty(exports, "__esModule", {
37
+ value: true
38
+ });
39
+ Object.defineProperty(exports, "AUTH_EMAIL_PROVIDER", {
40
+ enumerable: true,
41
+ get: function() {
42
+ return AUTH_EMAIL_PROVIDER;
43
+ }
44
+ });
45
+ const AUTH_EMAIL_PROVIDER = 'AUTH_EMAIL_PROVIDER';
@@ -1,6 +1,3 @@
1
- // =============================================================================
2
- // TOKEN INTERFACES
3
- // =============================================================================
4
1
  "use strict";
5
2
  Object.defineProperty(exports, "__esModule", {
6
3
  value: true
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
5
  _export_star(require("./authentication.interface"), exports);
6
+ _export_star(require("./auth-email-provider.interface"), exports);
6
7
  _export_star(require("./company-branch.interface"), exports);
7
8
  _export_star(require("./company.interface"), exports);
8
9
  _export_star(require("./user.interface"), exports);
10
+ _export_star(require("./user-enricher.interface"), exports);
9
11
  _export_star(require("./auth-module-options.interface"), exports);
10
12
  function _export_star(from, to) {
11
13
  Object.keys(from).forEach(function(k) {
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
@@ -12,7 +12,6 @@ const _modules = require("@flusys/nestjs-shared/modules");
12
12
  const _common = require("@nestjs/common");
13
13
  const _jwt = require("@nestjs/jwt");
14
14
  const _passport = require("@nestjs/passport");
15
- const _typeorm = require("@nestjs/typeorm");
16
15
  const _authconfigservice = require("../services/auth-config.service");
17
16
  const _authdatasourceprovider = require("../services/auth-datasource.provider");
18
17
  const _authconstants = require("../config/auth.constants");
@@ -34,7 +33,7 @@ let AuthModule = class AuthModule {
34
33
  return this.buildDynamicModule(options);
35
34
  }
36
35
  static forRootAsync(asyncOptions) {
37
- const { global = false, includeController = true, bootstrapAppConfig: { enableCompanyFeature } = {}, imports: externalImports = [] } = asyncOptions;
36
+ const { global = false, includeController = true, bootstrapAppConfig: { enableCompanyFeature } = {}, imports: externalImports = [], providers: additionalProviders = [] } = asyncOptions;
38
37
  const asyncProviders = this.createAsyncProviders(asyncOptions);
39
38
  // Build imports
40
39
  const imports = [
@@ -61,6 +60,7 @@ let AuthModule = class AuthModule {
61
60
  // Build providers
62
61
  const providers = [
63
62
  ...asyncProviders,
63
+ ...additionalProviders,
64
64
  // Config & Infrastructure
65
65
  _authconfigservice.AuthConfigService,
66
66
  _authdatasourceprovider.AuthDataSourceProvider,
@@ -68,6 +68,7 @@ let AuthModule = class AuthModule {
68
68
  _jwtstrategy.JwtStrategy,
69
69
  _guards.JwtAuthGuard,
70
70
  _services.AuthenticationService,
71
+ _services.AuthEmailService,
71
72
  // Interceptors
72
73
  _settokeninterceptor.SetToken,
73
74
  _cleartokeninterceptor.ClearToken,
@@ -87,6 +88,7 @@ let AuthModule = class AuthModule {
87
88
  _jwtstrategy.JwtStrategy,
88
89
  _guards.JwtAuthGuard,
89
90
  _services.AuthenticationService,
91
+ _services.AuthEmailService,
90
92
  _services.UserService
91
93
  ];
92
94
  if (enableCompanyFeature) {
@@ -102,7 +104,7 @@ let AuthModule = class AuthModule {
102
104
  };
103
105
  }
104
106
  static buildDynamicModule(options) {
105
- const { bootstrapAppConfig: { enableCompanyFeature } = {}, includeController = true, global = false } = options;
107
+ const { bootstrapAppConfig: { enableCompanyFeature } = {}, includeController = true, global = false, providers: additionalProviders = [] } = options;
106
108
  const imports = [
107
109
  _passport.PassportModule.register({
108
110
  defaultStrategy: 'jwt'
@@ -128,6 +130,7 @@ let AuthModule = class AuthModule {
128
130
  provide: _authconstants.AUTH_MODULE_OPTIONS,
129
131
  useValue: options
130
132
  },
133
+ ...additionalProviders,
131
134
  // Config & Infrastructure
132
135
  _authconfigservice.AuthConfigService,
133
136
  _authdatasourceprovider.AuthDataSourceProvider,
@@ -135,6 +138,7 @@ let AuthModule = class AuthModule {
135
138
  _jwtstrategy.JwtStrategy,
136
139
  _guards.JwtAuthGuard,
137
140
  _services.AuthenticationService,
141
+ _services.AuthEmailService,
138
142
  // Interceptors
139
143
  _settokeninterceptor.SetToken,
140
144
  _cleartokeninterceptor.ClearToken,
@@ -153,6 +157,7 @@ let AuthModule = class AuthModule {
153
157
  _jwtstrategy.JwtStrategy,
154
158
  _guards.JwtAuthGuard,
155
159
  _services.AuthenticationService,
160
+ _services.AuthEmailService,
156
161
  _services.UserService
157
162
  ];
158
163
  if (enableCompanyFeature) {
@@ -233,23 +238,6 @@ let AuthModule = class AuthModule {
233
238
  }
234
239
  ];
235
240
  }
236
- /**
237
- * Create repository providers that use AuthDataSourceProvider
238
- * This replaces TypeOrmModule.forFeature() functionality
239
- * Note: Must be REQUEST-scoped since AuthDataSourceProvider is REQUEST-scoped
240
- */ static getRepositoryProviders(enableCompanyFeature) {
241
- const entities = this.getEntities(enableCompanyFeature);
242
- return entities.map((entity)=>({
243
- provide: (0, _typeorm.getRepositoryToken)(entity),
244
- scope: _common.Scope.REQUEST,
245
- useFactory: async (dataSourceProvider)=>{
246
- return await dataSourceProvider.getRepository(entity);
247
- },
248
- inject: [
249
- _authdatasourceprovider.AuthDataSourceProvider
250
- ]
251
- }));
252
- }
253
241
  static getEntities(enableCompanyFeature = false) {
254
242
  const coreEntities = [
255
243
  _entities.User
@@ -39,83 +39,78 @@ function _ts_param(paramIndex, decorator) {
39
39
  };
40
40
  }
41
41
  let AuthConfigService = class AuthConfigService {
42
- // ==================== Database Mode ====================
43
- /**
44
- * Get database mode (single or multi-tenant)
45
- */ getDatabaseMode() {
42
+ // Database Mode
43
+ /** Get database mode (single or multi-tenant) */ getDatabaseMode() {
46
44
  return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
47
45
  }
48
- /**
49
- * Check if running in multi-tenant mode
50
- */ isMultiTenant() {
46
+ /** Check if running in multi-tenant mode */ isMultiTenant() {
51
47
  return this.getDatabaseMode() === 'multi-tenant';
52
48
  }
53
- // ==================== Feature Flags ====================
54
- /**
55
- * Check if company feature is enabled
56
- */ isCompanyFeatureEnabled() {
49
+ // Feature Flags
50
+ /** Check if company feature is enabled */ isCompanyFeatureEnabled() {
57
51
  return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
58
52
  }
59
- // ==================== JWT Configuration ====================
60
- /**
61
- * Get JWT secret key
62
- */ getJwtSecret() {
63
- return this.config.jwtSecret ?? 'default-secret-change-in-production';
53
+ // JWT Configuration
54
+ /** Get JWT secret key */ getJwtSecret() {
55
+ if (!this.config.jwtSecret) {
56
+ throw new _common.InternalServerErrorException('[AuthModule] JWT_SECRET is required - set via environment or module config');
57
+ }
58
+ return this.config.jwtSecret;
64
59
  }
65
- /**
66
- * Get JWT expiration time
67
- */ getJwtExpiration() {
60
+ /** Get JWT expiration time */ getJwtExpiration() {
68
61
  return this.config.jwtExpiration ?? '1h';
69
62
  }
70
- /**
71
- * Get refresh token secret key
72
- */ getRefreshTokenSecret() {
73
- return this.config.refreshTokenSecret ?? this.getJwtSecret();
74
- }
75
- /**
76
- * Get refresh token expiration time
77
- */ getRefreshTokenExpiration() {
63
+ /** Get refresh token secret key */ getRefreshTokenSecret() {
64
+ if (this.config.refreshTokenSecret) {
65
+ return this.config.refreshTokenSecret;
66
+ }
67
+ // Production: require separate refresh token secret for security
68
+ if (process.env.NODE_ENV === 'production') {
69
+ throw new _common.InternalServerErrorException('[AuthModule] REFRESH_TOKEN_SECRET is required in production - ' + 'using the same secret for access and refresh tokens is a security risk');
70
+ }
71
+ // Development: warn once about fallback to JWT secret
72
+ if (!this.refreshTokenSecretWarned) {
73
+ this.refreshTokenSecretWarned = true;
74
+ this.logger.warn('REFRESH_TOKEN_SECRET not configured - using JWT_SECRET as fallback. ' + 'For better security, configure a separate refresh token secret.');
75
+ }
76
+ return this.config.jwtSecret ?? this.getJwtSecret();
77
+ }
78
+ /** Get refresh token expiration time */ getRefreshTokenExpiration() {
78
79
  return this.config.refreshTokenExpiration ?? '7d';
79
80
  }
80
- /**
81
- * Get refresh token cookie name
82
- */ getRefreshTokenCookieName() {
81
+ /** Get refresh token cookie name */ getRefreshTokenCookieName() {
83
82
  return this.config.refreshTokenCookieName ?? 'fsn_refresh_token';
84
83
  }
85
- // ==================== Database Configuration ====================
86
- /**
87
- * Get default database config
88
- */ getDefaultDatabaseConfig() {
84
+ // Frontend Configuration
85
+ /** Get frontend URL for email links */ getFrontendUrl() {
86
+ return this.config.frontendUrl;
87
+ }
88
+ // Database Configuration
89
+ /** Get default database config */ getDefaultDatabaseConfig() {
89
90
  return this.config.defaultDatabaseConfig ?? this.config.tenantDefaultDatabaseConfig;
90
91
  }
91
- /**
92
- * Get tenant default database config (for multi-tenant)
93
- */ getTenantDefaultDatabaseConfig() {
92
+ /** Get tenant default database config (for multi-tenant) */ getTenantDefaultDatabaseConfig() {
94
93
  return this.config.tenantDefaultDatabaseConfig;
95
94
  }
96
- /**
97
- * Get registered tenants
98
- */ getTenants() {
95
+ /** Get registered tenants */ getTenants() {
99
96
  return this.config.tenants ?? [];
100
97
  }
101
- // ==================== Raw Options ====================
102
- /**
103
- * Get full module options
104
- */ getOptions() {
98
+ // Raw Options
99
+ /** Get full module options */ getOptions() {
105
100
  return {
106
101
  ...this.options
107
102
  };
108
103
  }
109
- /**
110
- * Get runtime config
111
- */ getConfig() {
104
+ /** Get runtime config */ getConfig() {
112
105
  return {
113
106
  ...this.config
114
107
  };
115
108
  }
116
109
  constructor(injectedOptions){
110
+ _define_property(this, "logger", new _common.Logger(AuthConfigService.name));
117
111
  _define_property(this, "options", void 0);
118
112
  _define_property(this, "config", void 0);
113
+ _define_property(this, "refreshTokenSecretWarned", false);
119
114
  this.options = injectedOptions ?? {
120
115
  global: false,
121
116
  includeController: true
@@ -83,11 +83,8 @@ function _ts_param(paramIndex, decorator) {
83
83
  };
84
84
  }
85
85
  let AuthDataSourceProvider = class AuthDataSourceProvider extends _modules.MultiTenantDataSourceService {
86
- // ==================== Override Static Cache Access Methods ====================
87
- /**
88
- * CRITICAL: Override to access Auth-specific static properties
89
- * Without this, parent class methods would access parent's static properties
90
- */ async getSingleDataSource() {
86
+ // Override Static Cache Access Methods
87
+ /** Override to access Auth-specific static properties */ async getSingleDataSource() {
91
88
  if (!AuthDataSourceProvider.singleDataSource) {
92
89
  if (AuthDataSourceProvider.singleConnectionLock) {
93
90
  return AuthDataSourceProvider.singleConnectionLock;
@@ -95,7 +92,7 @@ let AuthDataSourceProvider = class AuthDataSourceProvider extends _modules.Multi
95
92
  const lockPromise = (async ()=>{
96
93
  const config = this.getDefaultDatabaseConfig();
97
94
  if (!config) {
98
- throw new Error('Default database config is not available');
95
+ throw new _common.InternalServerErrorException('Default database config is not available');
99
96
  }
100
97
  const ds = await this.createDataSourceFromConfig(config);
101
98
  AuthDataSourceProvider.singleDataSource = ds;
@@ -111,9 +108,7 @@ let AuthDataSourceProvider = class AuthDataSourceProvider extends _modules.Multi
111
108
  }
112
109
  return AuthDataSourceProvider.singleDataSource;
113
110
  }
114
- /**
115
- * CRITICAL: Override to use Auth-specific static cache for tenant connections
116
- */ async getOrCreateTenantConnection(tenant) {
111
+ /** Override to use Auth-specific static cache for tenant connections */ async getOrCreateTenantConnection(tenant) {
117
112
  // Return existing initialized connection from Auth-specific cache
118
113
  const existing = AuthDataSourceProvider.tenantConnections.get(tenant.id);
119
114
  if (existing?.isInitialized) {
@@ -136,10 +131,8 @@ let AuthDataSourceProvider = class AuthDataSourceProvider extends _modules.Multi
136
131
  AuthDataSourceProvider.connectionLocks.delete(tenant.id);
137
132
  }
138
133
  }
139
- // ==================== Factory Methods ====================
140
- /**
141
- * Build parent options from AuthModuleOptions
142
- */ static buildParentOptions(options) {
134
+ // Factory Methods
135
+ /** Build parent options from AuthModuleOptions */ static buildParentOptions(options) {
143
136
  return {
144
137
  bootstrapAppConfig: options.bootstrapAppConfig,
145
138
  defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
@@ -147,31 +140,24 @@ let AuthDataSourceProvider = class AuthDataSourceProvider extends _modules.Multi
147
140
  tenants: options.config?.tenants
148
141
  };
149
142
  }
150
- // ==================== Feature Flags ====================
151
- /**
152
- * Get global enable company feature flag
153
- */ getEnableCompanyFeature() {
143
+ // Feature Flags
144
+ /** Get global enable company feature flag */ getEnableCompanyFeature() {
154
145
  return this.authOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
155
146
  }
156
- /**
157
- * Get enable company feature for specific tenant
158
- * Falls back to global setting if not specified per-tenant
159
- */ getEnableCompanyFeatureForTenant(tenant) {
147
+ /** Get enable company feature for specific tenant. Falls back to global setting. */ getEnableCompanyFeatureForTenant(tenant) {
160
148
  return tenant?.enableCompanyFeature ?? this.getEnableCompanyFeature();
161
149
  }
162
- /**
163
- * Get enable company feature for current request context
164
- */ getEnableCompanyFeatureForCurrentTenant() {
150
+ /** Get enable company feature for current request context */ getEnableCompanyFeatureForCurrentTenant() {
165
151
  return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
166
152
  }
167
- // ==================== Entity Management ====================
168
- /**
169
- * Get auth entities based on company feature flag
170
- */ async getAuthEntities(enableCompanyFeature) {
153
+ // Entity Management
154
+ /** Get auth entities based on company feature flag */ async getAuthEntities(enableCompanyFeature) {
171
155
  const enable = enableCompanyFeature ?? this.getEnableCompanyFeature();
172
- const { Company, CompanyBranch, User, UserCompanyPermission } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
156
+ const { Company, CompanyBranch, User, UserCompanyPermission, UserToken, PendingRegistration } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
173
157
  const coreEntities = [
174
- User
158
+ User,
159
+ UserToken,
160
+ PendingRegistration
175
161
  ];
176
162
  const companyEntities = enable ? [
177
163
  Company,
@@ -183,10 +169,8 @@ let AuthDataSourceProvider = class AuthDataSourceProvider extends _modules.Multi
183
169
  ...companyEntities
184
170
  ];
185
171
  }
186
- // ==================== Overrides ====================
187
- /**
188
- * Override to dynamically set entities based on tenant config
189
- */ async createDataSourceFromConfig(config) {
172
+ // Overrides
173
+ /** Override to dynamically set entities based on tenant config */ async createDataSourceFromConfig(config) {
190
174
  const currentTenant = this.getCurrentTenant();
191
175
  const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
192
176
  const entities = await this.getAuthEntities(enableCompanyFeature);