@lenne.tech/nest-server 11.7.0 → 11.7.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.
Files changed (120) hide show
  1. package/dist/config.env.js +17 -1
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/interfaces/server-options.interface.d.ts +35 -15
  4. package/dist/core/modules/auth/core-auth.controller.d.ts +1 -0
  5. package/dist/core/modules/auth/core-auth.controller.js +29 -3
  6. package/dist/core/modules/auth/core-auth.controller.js.map +1 -1
  7. package/dist/core/modules/auth/core-auth.module.js +14 -1
  8. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  9. package/dist/core/modules/auth/core-auth.resolver.d.ts +1 -0
  10. package/dist/core/modules/auth/core-auth.resolver.js +21 -3
  11. package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
  12. package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.d.ts +4 -0
  13. package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js +17 -0
  14. package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js.map +1 -0
  15. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.d.ts +9 -0
  16. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +74 -0
  17. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -0
  18. package/dist/core/modules/auth/interfaces/auth-provider.interface.d.ts +7 -0
  19. package/dist/core/modules/auth/interfaces/auth-provider.interface.js +5 -0
  20. package/dist/core/modules/auth/interfaces/auth-provider.interface.js.map +1 -0
  21. package/dist/core/modules/auth/interfaces/core-auth-user.interface.d.ts +1 -0
  22. package/dist/core/modules/auth/services/core-auth.service.d.ts +10 -1
  23. package/dist/core/modules/auth/services/core-auth.service.js +141 -9
  24. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  25. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.d.ts +31 -0
  26. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +153 -0
  27. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -0
  28. package/dist/core/modules/better-auth/better-auth-migration-status.model.d.ts +10 -0
  29. package/dist/core/modules/better-auth/better-auth-migration-status.model.js +57 -0
  30. package/dist/core/modules/better-auth/better-auth-migration-status.model.js.map +1 -0
  31. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js +1 -1
  32. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +1 -1
  33. package/dist/core/modules/better-auth/better-auth-user.mapper.d.ts +33 -0
  34. package/dist/core/modules/better-auth/better-auth-user.mapper.js +395 -0
  35. package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -1
  36. package/dist/core/modules/better-auth/better-auth.config.js +29 -10
  37. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  38. package/dist/core/modules/better-auth/better-auth.middleware.d.ts +1 -0
  39. package/dist/core/modules/better-auth/better-auth.middleware.js +55 -1
  40. package/dist/core/modules/better-auth/better-auth.middleware.js.map +1 -1
  41. package/dist/core/modules/better-auth/better-auth.module.d.ts +1 -1
  42. package/dist/core/modules/better-auth/better-auth.module.js +46 -18
  43. package/dist/core/modules/better-auth/better-auth.module.js.map +1 -1
  44. package/dist/core/modules/better-auth/better-auth.resolver.js +0 -11
  45. package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
  46. package/dist/core/modules/better-auth/better-auth.service.d.ts +22 -1
  47. package/dist/core/modules/better-auth/better-auth.service.js +209 -8
  48. package/dist/core/modules/better-auth/better-auth.service.js.map +1 -1
  49. package/dist/core/modules/better-auth/better-auth.types.d.ts +2 -0
  50. package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
  51. package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +1 -0
  52. package/dist/core/modules/better-auth/core-better-auth.controller.js +15 -2
  53. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
  54. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +7 -0
  55. package/dist/core/modules/better-auth/core-better-auth.resolver.js +72 -12
  56. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
  57. package/dist/core/modules/better-auth/index.d.ts +1 -0
  58. package/dist/core/modules/better-auth/index.js +1 -0
  59. package/dist/core/modules/better-auth/index.js.map +1 -1
  60. package/dist/core/modules/user/core-user.service.d.ts +7 -1
  61. package/dist/core/modules/user/core-user.service.js +57 -3
  62. package/dist/core/modules/user/core-user.service.js.map +1 -1
  63. package/dist/core/modules/user/interfaces/core-user-service-options.interface.d.ts +4 -0
  64. package/dist/core/modules/user/interfaces/core-user-service-options.interface.js +3 -0
  65. package/dist/core/modules/user/interfaces/core-user-service-options.interface.js.map +1 -0
  66. package/dist/core.module.d.ts +3 -0
  67. package/dist/core.module.js +136 -55
  68. package/dist/core.module.js.map +1 -1
  69. package/dist/index.d.ts +5 -0
  70. package/dist/index.js +5 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/server/modules/auth/auth.resolver.js +2 -0
  73. package/dist/server/modules/auth/auth.resolver.js.map +1 -1
  74. package/dist/server/modules/better-auth/better-auth.module.d.ts +1 -1
  75. package/dist/server/modules/better-auth/better-auth.module.js +2 -1
  76. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
  77. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +5 -0
  78. package/dist/server/modules/better-auth/better-auth.resolver.js +27 -11
  79. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -1
  80. package/dist/server/modules/user/user.controller.js +0 -8
  81. package/dist/server/modules/user/user.controller.js.map +1 -1
  82. package/dist/server/modules/user/user.service.d.ts +3 -1
  83. package/dist/server/modules/user/user.service.js +7 -3
  84. package/dist/server/modules/user/user.service.js.map +1 -1
  85. package/dist/tsconfig.build.tsbuildinfo +1 -1
  86. package/package.json +1 -1
  87. package/src/config.env.ts +32 -2
  88. package/src/core/common/interfaces/server-options.interface.ts +304 -58
  89. package/src/core/modules/auth/core-auth.controller.ts +94 -6
  90. package/src/core/modules/auth/core-auth.module.ts +15 -1
  91. package/src/core/modules/auth/core-auth.resolver.ts +71 -3
  92. package/src/core/modules/auth/exceptions/legacy-auth-disabled.exception.ts +35 -0
  93. package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +109 -0
  94. package/src/core/modules/auth/interfaces/auth-provider.interface.ts +86 -0
  95. package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +6 -0
  96. package/src/core/modules/auth/services/core-auth.service.ts +245 -6
  97. package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +283 -0
  98. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +255 -0
  99. package/src/core/modules/better-auth/README.md +565 -208
  100. package/src/core/modules/better-auth/better-auth-migration-status.model.ts +73 -0
  101. package/src/core/modules/better-auth/better-auth-rate-limiter.service.ts +1 -1
  102. package/src/core/modules/better-auth/better-auth-user.mapper.ts +737 -0
  103. package/src/core/modules/better-auth/better-auth.config.ts +45 -15
  104. package/src/core/modules/better-auth/better-auth.middleware.ts +85 -2
  105. package/src/core/modules/better-auth/better-auth.module.ts +83 -27
  106. package/src/core/modules/better-auth/better-auth.resolver.ts +0 -11
  107. package/src/core/modules/better-auth/better-auth.service.ts +367 -12
  108. package/src/core/modules/better-auth/better-auth.types.ts +16 -0
  109. package/src/core/modules/better-auth/core-better-auth.controller.ts +44 -3
  110. package/src/core/modules/better-auth/core-better-auth.resolver.ts +136 -16
  111. package/src/core/modules/better-auth/index.ts +1 -0
  112. package/src/core/modules/user/core-user.service.ts +131 -4
  113. package/src/core/modules/user/interfaces/core-user-service-options.interface.ts +15 -0
  114. package/src/core.module.ts +264 -76
  115. package/src/index.ts +5 -0
  116. package/src/server/modules/auth/auth.resolver.ts +8 -0
  117. package/src/server/modules/better-auth/better-auth.module.ts +9 -3
  118. package/src/server/modules/better-auth/better-auth.resolver.ts +18 -11
  119. package/src/server/modules/user/user.controller.ts +1 -9
  120. package/src/server/modules/user/user.service.ts +4 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "11.7.0",
3
+ "version": "11.7.2",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
package/src/config.env.ts CHANGED
@@ -14,6 +14,16 @@ const config: { [env: string]: IServerOptions } = {
14
14
  // Development environment
15
15
  // ===========================================================================
16
16
  development: {
17
+ // Legacy Auth endpoint controls (for migration to BetterAuth)
18
+ // Set to false after all users have migrated to BetterAuth (IAM)
19
+ // See: .claude/rules/module-deprecation.md
20
+ auth: {
21
+ legacyEndpoints: {
22
+ enabled: true, // Set to false to disable legacy auth endpoints (returns HTTP 410)
23
+ // graphql: true, // Optionally disable only GraphQL endpoints
24
+ // rest: true, // Optionally disable only REST endpoints
25
+ },
26
+ },
17
27
  automaticObjectIdFiltering: true,
18
28
  betterAuth: {
19
29
  basePath: '/iam',
@@ -162,11 +172,21 @@ const config: { [env: string]: IServerOptions } = {
162
172
  // Local environment
163
173
  // ===========================================================================
164
174
  local: {
175
+ // Legacy Auth endpoint controls (for migration to BetterAuth)
176
+ // Set to false after all users have migrated to BetterAuth (IAM)
177
+ // See: .claude/rules/module-deprecation.md
178
+ auth: {
179
+ legacyEndpoints: {
180
+ enabled: true, // Set to false to disable legacy auth endpoints (returns HTTP 410)
181
+ // graphql: true, // Optionally disable only GraphQL endpoints
182
+ // rest: true, // Optionally disable only REST endpoints
183
+ },
184
+ },
165
185
  automaticObjectIdFiltering: true,
166
186
  betterAuth: {
167
187
  basePath: '/iam',
168
188
  baseUrl: 'http://localhost:3000',
169
- // enabled: true by default - set false to explicitly disable
189
+ enabled: true, // Enable for Scenario 2 (Legacy + IAM) testing
170
190
  jwt: {
171
191
  enabled: true,
172
192
  expiresIn: '15m',
@@ -179,7 +199,7 @@ const config: { [env: string]: IServerOptions } = {
179
199
  },
180
200
  rateLimit: {
181
201
  enabled: true,
182
- max: 20,
202
+ max: 100, // Higher limit for local testing
183
203
  message: 'Too many requests, please try again later.',
184
204
  skipEndpoints: ['/session', '/callback'],
185
205
  strictEndpoints: ['/sign-in', '/sign-up', '/forgot-password', '/reset-password'],
@@ -321,6 +341,16 @@ const config: { [env: string]: IServerOptions } = {
321
341
  // Production environment
322
342
  // ===========================================================================
323
343
  production: {
344
+ // Legacy Auth endpoint controls (for migration to BetterAuth)
345
+ // Set to false after all users have migrated to BetterAuth (IAM)
346
+ // See: .claude/rules/module-deprecation.md
347
+ auth: {
348
+ legacyEndpoints: {
349
+ enabled: process.env.LEGACY_AUTH_ENABLED !== 'false', // Disable via env var
350
+ // graphql: true, // Optionally disable only GraphQL endpoints
351
+ // rest: true, // Optionally disable only REST endpoints
352
+ },
353
+ },
324
354
  automaticObjectIdFiltering: true,
325
355
  betterAuth: {
326
356
  basePath: '/iam',
@@ -22,6 +22,170 @@ import { MailjetOptions } from './mailjet-options.interface';
22
22
  */
23
23
  export type BetterAuthFieldType = 'boolean' | 'date' | 'json' | 'number' | 'number[]' | 'string' | 'string[]';
24
24
 
25
+ /**
26
+ * Interface for Auth configuration
27
+ *
28
+ * This configuration controls the authentication system behavior.
29
+ * In v11.x, Legacy Auth (CoreAuthService) is the default.
30
+ * In a future version, BetterAuth (IAM) will become the default.
31
+ *
32
+ * @since 11.7.1
33
+ *
34
+ * ## Migration Roadmap
35
+ *
36
+ * ### v11.x (Current)
37
+ * - Legacy Auth is the default and required for GraphQL Subscriptions
38
+ * - BetterAuth can be used alongside Legacy Auth
39
+ * - Use `legacyEndpoints.enabled: false` after all users migrated to IAM
40
+ *
41
+ * ### Future Version (Planned)
42
+ * - BetterAuth becomes the default
43
+ * - Legacy Auth becomes optional (must be explicitly enabled)
44
+ * - CoreModule.forRoot signature simplifies to `CoreModule.forRoot(options)`
45
+ *
46
+ * @see https://github.com/lenneTech/nest-server/blob/develop/.claude/rules/module-deprecation.md
47
+ */
48
+ export interface IAuth {
49
+ /**
50
+ * Configuration for legacy auth endpoints
51
+ *
52
+ * Legacy endpoints include:
53
+ * - GraphQL: signIn, signUp, signOut, refreshToken mutations
54
+ * - REST: /api/auth/* endpoints
55
+ *
56
+ * These can be disabled once all users have migrated to BetterAuth (IAM).
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * auth: {
61
+ * legacyEndpoints: {
62
+ * enabled: false // Disable all legacy endpoints after migration
63
+ * }
64
+ * }
65
+ * ```
66
+ */
67
+ legacyEndpoints?: IAuthLegacyEndpoints;
68
+
69
+ /**
70
+ * Prevent user enumeration via unified error messages
71
+ *
72
+ * When enabled, authentication errors return a generic "Invalid credentials"
73
+ * message instead of specific messages like "Unknown email" or "Wrong password".
74
+ *
75
+ * This prevents attackers from determining whether an email address exists
76
+ * in the system, but reduces UX clarity for legitimate users.
77
+ *
78
+ * @since 11.7.x
79
+ * @default false (backward compatible - specific error messages)
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * auth: {
84
+ * preventUserEnumeration: true // Returns "Invalid credentials" for all auth errors
85
+ * }
86
+ * ```
87
+ */
88
+ preventUserEnumeration?: boolean;
89
+
90
+ /**
91
+ * Rate limiting configuration for Legacy Auth endpoints
92
+ *
93
+ * Protects against brute-force attacks on signIn, signUp, and other
94
+ * authentication endpoints.
95
+ *
96
+ * Follows the same pattern as `betterAuth.rateLimit`.
97
+ *
98
+ * @since 11.7.x
99
+ * @default { enabled: false }
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * auth: {
104
+ * rateLimit: {
105
+ * enabled: true,
106
+ * max: 10,
107
+ * windowSeconds: 60,
108
+ * message: 'Too many login attempts, please try again later.',
109
+ * }
110
+ * }
111
+ * ```
112
+ */
113
+ rateLimit?: IAuthRateLimit;
114
+ }
115
+
116
+ /**
117
+ * Interface for Legacy Auth endpoints configuration
118
+ *
119
+ * These endpoints are part of the Legacy Auth system (CoreAuthService).
120
+ * In a future version, BetterAuth (IAM) will become the default and these endpoints
121
+ * can be disabled once all users have migrated.
122
+ *
123
+ * @since 11.7.1
124
+ * @see https://github.com/lenneTech/nest-server/blob/develop/.claude/rules/module-deprecation.md
125
+ */
126
+ export interface IAuthLegacyEndpoints {
127
+ /**
128
+ * Whether legacy auth endpoints are enabled.
129
+ *
130
+ * Set to false to disable all legacy auth endpoints (GraphQL and REST).
131
+ * Use this after all users have migrated to BetterAuth (IAM).
132
+ *
133
+ * Check migration status via the `betterAuthMigrationStatus` query.
134
+ *
135
+ * @default true
136
+ */
137
+ enabled?: boolean;
138
+
139
+ /**
140
+ * Whether legacy GraphQL auth endpoints are enabled.
141
+ * Affects: signIn, signUp, signOut, refreshToken mutations
142
+ *
143
+ * @default true (inherits from `enabled`)
144
+ */
145
+ graphql?: boolean;
146
+
147
+ /**
148
+ * Whether legacy REST auth endpoints are enabled.
149
+ * Affects: /api/auth/sign-in, /api/auth/sign-up, etc.
150
+ *
151
+ * @default true (inherits from `enabled`)
152
+ */
153
+ rest?: boolean;
154
+ }
155
+
156
+ /**
157
+ * Interface for Legacy Auth rate limiting configuration
158
+ *
159
+ * Same structure as IBetterAuthRateLimit for consistency.
160
+ *
161
+ * @since 11.7.x
162
+ */
163
+ export interface IAuthRateLimit {
164
+ /**
165
+ * Whether rate limiting is enabled
166
+ * @default false
167
+ */
168
+ enabled?: boolean;
169
+
170
+ /**
171
+ * Maximum number of requests within the time window
172
+ * @default 10
173
+ */
174
+ max?: number;
175
+
176
+ /**
177
+ * Custom message when rate limit is exceeded
178
+ * @default 'Too many requests, please try again later.'
179
+ */
180
+ message?: string;
181
+
182
+ /**
183
+ * Time window in seconds
184
+ * @default 60
185
+ */
186
+ windowSeconds?: number;
187
+ }
188
+
25
189
  /**
26
190
  * Interface for better-auth configuration
27
191
  */
@@ -110,22 +274,29 @@ export interface IBetterAuth {
110
274
 
111
275
  /**
112
276
  * JWT plugin configuration for API clients.
113
- * Enabled by default when this config block is present.
114
- * Set `enabled: false` to explicitly disable.
277
+ *
278
+ * **Default: Enabled** - JWT is enabled by default when BetterAuth is enabled.
279
+ * This ensures a minimal config (`betterAuth: true`) provides full functionality.
280
+ *
281
+ * Accepts:
282
+ * - `true` or `{}`: Enable with defaults (same as not specifying)
283
+ * - `{ expiresIn: '1h' }`: Enable with custom settings
284
+ * - `false` or `{ enabled: false }`: Explicitly disable
285
+ * - `undefined`: Enabled with defaults (JWT is on by default)
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * // JWT is enabled by default, no config needed
290
+ * betterAuth: true,
291
+ *
292
+ * // Customize JWT expiry
293
+ * betterAuth: { jwt: { expiresIn: '1h' } },
294
+ *
295
+ * // Explicitly disable JWT (session-only mode)
296
+ * betterAuth: { jwt: false },
297
+ * ```
115
298
  */
116
- jwt?: {
117
- /**
118
- * Whether JWT plugin is enabled.
119
- * @default true (when jwt config block is present)
120
- */
121
- enabled?: boolean;
122
-
123
- /**
124
- * JWT expiration time
125
- * @default '15m'
126
- */
127
- expiresIn?: string;
128
- };
299
+ jwt?: boolean | IBetterAuthJwtConfig;
129
300
 
130
301
  /**
131
302
  * Advanced Better-Auth options passthrough.
@@ -158,34 +329,22 @@ export interface IBetterAuth {
158
329
 
159
330
  /**
160
331
  * Passkey/WebAuthn configuration.
161
- * Enabled by default when this config block is present.
162
- * Set `enabled: false` to explicitly disable.
332
+ *
333
+ * Accepts:
334
+ * - `true` or `{}`: Enable with defaults
335
+ * - `{ rpName: 'My App' }`: Enable with custom settings
336
+ * - `false` or `{ enabled: false }`: Disable
337
+ * - `undefined`: Disabled (default)
338
+ *
339
+ * @example
340
+ * ```typescript
341
+ * passkey: true, // Enable with defaults
342
+ * passkey: {}, // Enable with defaults
343
+ * passkey: { rpName: 'My App', rpId: 'example.com' }, // Enable with custom settings
344
+ * passkey: false, // Disable
345
+ * ```
163
346
  */
164
- passkey?: {
165
- /**
166
- * Whether passkey authentication is enabled.
167
- * @default true (when passkey config block is present)
168
- */
169
- enabled?: boolean;
170
-
171
- /**
172
- * Origin URL for WebAuthn
173
- * e.g. 'http://localhost:3000'
174
- */
175
- origin?: string;
176
-
177
- /**
178
- * Relying Party ID (usually the domain)
179
- * e.g. 'localhost' or 'example.com'
180
- */
181
- rpId?: string;
182
-
183
- /**
184
- * Relying Party Name (displayed to users)
185
- * e.g. 'My Application'
186
- */
187
- rpName?: string;
188
- };
347
+ passkey?: boolean | IBetterAuthPasskeyConfig;
189
348
 
190
349
  /**
191
350
  * Additional Better-Auth plugins to include.
@@ -246,22 +405,68 @@ export interface IBetterAuth {
246
405
 
247
406
  /**
248
407
  * Two-factor authentication configuration.
249
- * Enabled by default when this config block is present.
250
- * Set `enabled: false` to explicitly disable.
408
+ *
409
+ * Accepts:
410
+ * - `true` or `{}`: Enable with defaults
411
+ * - `{ appName: 'My App' }`: Enable with custom settings
412
+ * - `false` or `{ enabled: false }`: Disable
413
+ * - `undefined`: Disabled (default)
414
+ *
415
+ * @example
416
+ * ```typescript
417
+ * twoFactor: true, // Enable with defaults
418
+ * twoFactor: {}, // Enable with defaults
419
+ * twoFactor: { appName: 'My App' }, // Enable with custom app name
420
+ * twoFactor: false, // Disable
421
+ * ```
251
422
  */
252
- twoFactor?: {
253
- /**
254
- * App name shown in authenticator apps
255
- * e.g. 'My Application'
256
- */
257
- appName?: string;
423
+ twoFactor?: boolean | IBetterAuthTwoFactorConfig;
424
+ }
258
425
 
259
- /**
260
- * Whether 2FA is enabled.
261
- * @default true (when twoFactor config block is present)
262
- */
263
- enabled?: boolean;
264
- };
426
+ /**
427
+ * JWT plugin configuration for Better-Auth
428
+ */
429
+ export interface IBetterAuthJwtConfig {
430
+ /**
431
+ * Whether JWT plugin is enabled.
432
+ * @default true (when config block is present)
433
+ */
434
+ enabled?: boolean;
435
+
436
+ /**
437
+ * JWT expiration time
438
+ * @default '15m'
439
+ */
440
+ expiresIn?: string;
441
+ }
442
+
443
+ /**
444
+ * Passkey/WebAuthn plugin configuration for Better-Auth
445
+ */
446
+ export interface IBetterAuthPasskeyConfig {
447
+ /**
448
+ * Whether passkey authentication is enabled.
449
+ * @default true (when config block is present)
450
+ */
451
+ enabled?: boolean;
452
+
453
+ /**
454
+ * Origin URL for WebAuthn
455
+ * e.g. 'http://localhost:3000'
456
+ */
457
+ origin?: string;
458
+
459
+ /**
460
+ * Relying Party ID (usually the domain)
461
+ * e.g. 'localhost' or 'example.com'
462
+ */
463
+ rpId?: string;
464
+
465
+ /**
466
+ * Relying Party Name (displayed to users)
467
+ * e.g. 'My Application'
468
+ */
469
+ rpName?: string;
265
470
  }
266
471
 
267
472
  /**
@@ -341,6 +546,23 @@ export interface IBetterAuthSocialProvider {
341
546
  enabled?: boolean;
342
547
  }
343
548
 
549
+ /**
550
+ * Two-factor authentication plugin configuration for Better-Auth
551
+ */
552
+ export interface IBetterAuthTwoFactorConfig {
553
+ /**
554
+ * App name shown in authenticator apps
555
+ * e.g. 'My Application'
556
+ */
557
+ appName?: string;
558
+
559
+ /**
560
+ * Whether 2FA is enabled.
561
+ * @default true (when config block is present)
562
+ */
563
+ enabled?: boolean;
564
+ }
565
+
344
566
  /**
345
567
  * Interface for additional user fields in Better-Auth
346
568
  * @see https://www.better-auth.com/docs/concepts/users-accounts#additional-fields
@@ -413,6 +635,17 @@ export interface IJwt {
413
635
  * Options for the server
414
636
  */
415
637
  export interface IServerOptions {
638
+ /**
639
+ * Authentication system configuration
640
+ *
641
+ * Controls Legacy Auth endpoints and behavior.
642
+ * In a future version, this will also control BetterAuth as the default system.
643
+ *
644
+ * @since 11.7.1
645
+ * @see IAuth
646
+ */
647
+ auth?: IAuth;
648
+
416
649
  /**
417
650
  * Automatically detect ObjectIds in string values in FilterQueries
418
651
  * and expand them as OR query with string and ObjectId.
@@ -423,10 +656,23 @@ export interface IServerOptions {
423
656
  automaticObjectIdFiltering?: boolean;
424
657
 
425
658
  /**
426
- * Configuration for better-auth authentication framework
659
+ * Configuration for better-auth authentication framework.
427
660
  * See: https://better-auth.com
661
+ *
662
+ * Accepts:
663
+ * - `true`: Enable with all defaults (including JWT)
664
+ * - `false`: Disable BetterAuth completely
665
+ * - `{ ... }`: Enable with custom configuration
666
+ * - `undefined`: Disabled (default for backward compatibility)
667
+ *
668
+ * @example
669
+ * ```typescript
670
+ * betterAuth: true, // Enable with defaults (JWT enabled)
671
+ * betterAuth: { baseUrl: 'https://example.com' }, // Custom config
672
+ * betterAuth: false, // Explicitly disabled
673
+ * ```
428
674
  */
429
- betterAuth?: IBetterAuth;
675
+ betterAuth?: boolean | IBetterAuth;
430
676
 
431
677
  /**
432
678
  * Configuration for Brevo
@@ -1,9 +1,12 @@
1
1
  import { Body, Controller, Get, ParseBoolPipe, Post, Query, Res, UseGuards } from '@nestjs/common';
2
2
  import {
3
- ApiBody, ApiCreatedResponse,
3
+ ApiBody,
4
+ ApiCreatedResponse,
5
+ ApiGoneResponse,
4
6
  ApiOkResponse,
5
7
  ApiOperation,
6
8
  ApiQuery,
9
+ ApiTooManyRequestsResponse,
7
10
  } from '@nestjs/swagger';
8
11
  import { Response as ResponseType } from 'express';
9
12
 
@@ -14,13 +17,38 @@ import { RoleEnum } from '../../common/enums/role.enum';
14
17
  import { ConfigService } from '../../common/services/config.service';
15
18
  import { AuthGuardStrategy } from './auth-guard-strategy.enum';
16
19
  import { CoreAuthModel } from './core-auth.model';
20
+ import { LegacyAuthDisabledException } from './exceptions/legacy-auth-disabled.exception';
17
21
  import { AuthGuard } from './guards/auth.guard';
22
+ import { LegacyAuthRateLimitGuard } from './guards/legacy-auth-rate-limit.guard';
18
23
  import { CoreAuthSignInInput } from './inputs/core-auth-sign-in.input';
19
24
  import { CoreAuthSignUpInput } from './inputs/core-auth-sign-up.input';
20
25
  import { ICoreAuthUser } from './interfaces/core-auth-user.interface';
21
26
  import { CoreAuthService } from './services/core-auth.service';
22
27
  import { Tokens } from './tokens.decorator';
23
28
 
29
+ /**
30
+ * Authentication controller for REST endpoints
31
+ *
32
+ * This controller provides Legacy Auth endpoints via REST.
33
+ * In a future version, BetterAuth (IAM) will become the default.
34
+ *
35
+ * ## Disabling Legacy Endpoints
36
+ *
37
+ * After all users have migrated to BetterAuth (IAM), these endpoints
38
+ * can be disabled via configuration:
39
+ *
40
+ * ```typescript
41
+ * auth: {
42
+ * legacyEndpoints: {
43
+ * enabled: false, // Disable all legacy endpoints
44
+ * // or
45
+ * rest: false // Disable only REST endpoints
46
+ * }
47
+ * }
48
+ * ```
49
+ *
50
+ * @see https://github.com/lenneTech/nest-server/blob/develop/.claude/rules/module-deprecation.md
51
+ */
24
52
  @ApiCommonErrorResponses()
25
53
  @Controller('auth')
26
54
  @Roles(RoleEnum.ADMIN)
@@ -33,63 +61,123 @@ export class CoreAuthController {
33
61
  protected readonly configService: ConfigService,
34
62
  ) {}
35
63
 
64
+ // ===========================================================================
65
+ // Helper - Legacy Endpoint Check
66
+ // ===========================================================================
67
+
68
+ /**
69
+ * Check if legacy REST endpoints are enabled
70
+ *
71
+ * Throws LegacyAuthDisabledException if:
72
+ * - config.auth.legacyEndpoints.enabled is false
73
+ * - config.auth.legacyEndpoints.rest is false
74
+ *
75
+ * @throws LegacyAuthDisabledException
76
+ */
77
+ protected checkLegacyRESTEnabled(endpointName: string): void {
78
+ const authConfig = this.configService.getFastButReadOnly('auth');
79
+ const legacyConfig = authConfig?.legacyEndpoints;
80
+
81
+ // Check if legacy endpoints are globally disabled
82
+ if (legacyConfig?.enabled === false) {
83
+ throw new LegacyAuthDisabledException(endpointName);
84
+ }
85
+
86
+ // Check if REST endpoints specifically are disabled
87
+ if (legacyConfig?.rest === false) {
88
+ throw new LegacyAuthDisabledException(endpointName);
89
+ }
90
+ }
91
+
36
92
  /**
37
93
  * Logout user (from specific device)
94
+ *
95
+ * @deprecated Will be replaced by BetterAuth signOut in a future version
96
+ * @throws LegacyAuthDisabledException if legacy endpoints are disabled
38
97
  */
98
+ @ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
39
99
  @ApiOkResponse({ type: Boolean })
40
100
  @ApiOperation({ description: 'Logs a user out from a specific device' })
41
101
  @ApiQuery({ description: 'If all devices should be logged out,', name: 'allDevices', required: false, type: Boolean })
102
+ @ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
42
103
  @Get('logout')
43
- @Roles(RoleEnum.S_EVERYONE)
44
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
104
+ @Roles(RoleEnum.S_USER)
105
+ @UseGuards(LegacyAuthRateLimitGuard)
45
106
  async logout(
46
107
  @CurrentUser() currentUser: ICoreAuthUser,
47
108
  @Tokens('token') token: string,
48
109
  @Res({ passthrough: true }) res: ResponseType,
49
110
  @Query('allDevices', new ParseBoolPipe({ optional: true })) allDevices?: boolean,
50
111
  ): Promise<boolean> {
112
+ this.checkLegacyRESTEnabled('logout');
51
113
  const result = await this.authService.logout(token, { allDevices, currentUser });
52
114
  return this.processCookies(res, result);
53
115
  }
54
116
 
55
117
  /**
56
118
  * Refresh token (for specific device)
119
+ *
120
+ * @deprecated Will be replaced by BetterAuth session refresh in a future version
121
+ * @throws LegacyAuthDisabledException if legacy endpoints are disabled
57
122
  */
123
+ @ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
58
124
  @ApiOkResponse({ type: CoreAuthModel })
59
125
  @ApiOperation({ description: 'Refresh token (for specific device)' })
126
+ @ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
60
127
  @Get('refresh-token')
61
128
  @Roles(RoleEnum.S_EVERYONE)
62
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT_REFRESH))
129
+ @UseGuards(LegacyAuthRateLimitGuard, AuthGuard(AuthGuardStrategy.JWT_REFRESH))
63
130
  async refreshToken(
64
131
  @CurrentUser() user: ICoreAuthUser,
65
132
  @Tokens('refreshToken') refreshToken: string,
66
133
  @Res({ passthrough: true }) res: ResponseType,
67
134
  ): Promise<CoreAuthModel> {
135
+ this.checkLegacyRESTEnabled('refresh-token');
68
136
  const result = await this.authService.refreshTokens(user, refreshToken);
69
137
  return this.processCookies(res, result);
70
138
  }
71
139
 
72
140
  /**
73
141
  * Sign in user via email and password (on specific device)
142
+ *
143
+ * @deprecated Will be replaced by BetterAuth signIn in a future version
144
+ * @throws LegacyAuthDisabledException if legacy endpoints are disabled
74
145
  */
75
146
  @ApiCreatedResponse({ description: 'Signed in successfully', type: CoreAuthModel })
147
+ @ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
76
148
  @ApiOperation({ description: 'Sign in via email and password' })
149
+ @ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
77
150
  @Post('signin')
78
151
  @Roles(RoleEnum.S_EVERYONE)
79
- async signIn(@Res({ passthrough: true }) res: ResponseType, @Body() input: CoreAuthSignInInput): Promise<CoreAuthModel> {
152
+ @UseGuards(LegacyAuthRateLimitGuard)
153
+ async signIn(
154
+ @Res({ passthrough: true }) res: ResponseType,
155
+ @Body() input: CoreAuthSignInInput,
156
+ ): Promise<CoreAuthModel> {
157
+ this.checkLegacyRESTEnabled('signin');
80
158
  const result = await this.authService.signIn(input);
81
159
  return this.processCookies(res, result);
82
160
  }
83
161
 
84
162
  /**
85
163
  * Register a new user account (on specific device)
164
+ *
165
+ * @deprecated Will be replaced by BetterAuth signUp in a future version
166
+ * @throws LegacyAuthDisabledException if legacy endpoints are disabled
86
167
  */
87
168
  @ApiBody({ type: CoreAuthSignUpInput })
88
169
  @ApiCreatedResponse({ type: CoreAuthSignUpInput })
170
+ @ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
89
171
  @ApiOperation({ description: 'Sign up via email and password' })
172
+ @ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
90
173
  @Post('signup')
91
174
  @Roles(RoleEnum.S_EVERYONE)
92
- async signUp(@Res({ passthrough: true }) res: ResponseType, @Body() input: CoreAuthSignUpInput): Promise<CoreAuthModel> {
175
+ @UseGuards(LegacyAuthRateLimitGuard)
176
+ async signUp(
177
+ @Res({ passthrough: true }) res: ResponseType,
178
+ @Body() input: CoreAuthSignUpInput,
179
+ ): Promise<CoreAuthModel> {
180
+ this.checkLegacyRESTEnabled('signup');
93
181
  const result = await this.authService.signUp(input);
94
182
  return this.processCookies(res, result);
95
183
  }