@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.
- package/dist/config.env.js +17 -1
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +35 -15
- package/dist/core/modules/auth/core-auth.controller.d.ts +1 -0
- package/dist/core/modules/auth/core-auth.controller.js +29 -3
- package/dist/core/modules/auth/core-auth.controller.js.map +1 -1
- package/dist/core/modules/auth/core-auth.module.js +14 -1
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/core-auth.resolver.d.ts +1 -0
- package/dist/core/modules/auth/core-auth.resolver.js +21 -3
- package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
- package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.d.ts +4 -0
- package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js +17 -0
- package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js.map +1 -0
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.d.ts +9 -0
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +74 -0
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -0
- package/dist/core/modules/auth/interfaces/auth-provider.interface.d.ts +7 -0
- package/dist/core/modules/auth/interfaces/auth-provider.interface.js +5 -0
- package/dist/core/modules/auth/interfaces/auth-provider.interface.js.map +1 -0
- package/dist/core/modules/auth/interfaces/core-auth-user.interface.d.ts +1 -0
- package/dist/core/modules/auth/services/core-auth.service.d.ts +10 -1
- package/dist/core/modules/auth/services/core-auth.service.js +141 -9
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.d.ts +31 -0
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +153 -0
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-migration-status.model.d.ts +10 -0
- package/dist/core/modules/better-auth/better-auth-migration-status.model.js +57 -0
- package/dist/core/modules/better-auth/better-auth-migration-status.model.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js +1 -1
- package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth-user.mapper.d.ts +33 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.js +395 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.config.js +29 -10
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.middleware.d.ts +1 -0
- package/dist/core/modules/better-auth/better-auth.middleware.js +55 -1
- package/dist/core/modules/better-auth/better-auth.middleware.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.module.d.ts +1 -1
- package/dist/core/modules/better-auth/better-auth.module.js +46 -18
- package/dist/core/modules/better-auth/better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.resolver.js +0 -11
- package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.service.d.ts +22 -1
- package/dist/core/modules/better-auth/better-auth.service.js +209 -8
- package/dist/core/modules/better-auth/better-auth.service.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.types.d.ts +2 -0
- package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +1 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js +15 -2
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +7 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.js +72 -12
- package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
- package/dist/core/modules/better-auth/index.d.ts +1 -0
- package/dist/core/modules/better-auth/index.js +1 -0
- package/dist/core/modules/better-auth/index.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +7 -1
- package/dist/core/modules/user/core-user.service.js +57 -3
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core/modules/user/interfaces/core-user-service-options.interface.d.ts +4 -0
- package/dist/core/modules/user/interfaces/core-user-service-options.interface.js +3 -0
- package/dist/core/modules/user/interfaces/core-user-service-options.interface.js.map +1 -0
- package/dist/core.module.d.ts +3 -0
- package/dist/core.module.js +136 -55
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/auth/auth.resolver.js +2 -0
- package/dist/server/modules/auth/auth.resolver.js.map +1 -1
- package/dist/server/modules/better-auth/better-auth.module.d.ts +1 -1
- package/dist/server/modules/better-auth/better-auth.module.js +2 -1
- package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
- package/dist/server/modules/better-auth/better-auth.resolver.d.ts +5 -0
- package/dist/server/modules/better-auth/better-auth.resolver.js +27 -11
- package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -1
- package/dist/server/modules/user/user.controller.js +0 -8
- package/dist/server/modules/user/user.controller.js.map +1 -1
- package/dist/server/modules/user/user.service.d.ts +3 -1
- package/dist/server/modules/user/user.service.js +7 -3
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config.env.ts +32 -2
- package/src/core/common/interfaces/server-options.interface.ts +304 -58
- package/src/core/modules/auth/core-auth.controller.ts +94 -6
- package/src/core/modules/auth/core-auth.module.ts +15 -1
- package/src/core/modules/auth/core-auth.resolver.ts +71 -3
- package/src/core/modules/auth/exceptions/legacy-auth-disabled.exception.ts +35 -0
- package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +109 -0
- package/src/core/modules/auth/interfaces/auth-provider.interface.ts +86 -0
- package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +6 -0
- package/src/core/modules/auth/services/core-auth.service.ts +245 -6
- package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +283 -0
- package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +255 -0
- package/src/core/modules/better-auth/README.md +565 -208
- package/src/core/modules/better-auth/better-auth-migration-status.model.ts +73 -0
- package/src/core/modules/better-auth/better-auth-rate-limiter.service.ts +1 -1
- package/src/core/modules/better-auth/better-auth-user.mapper.ts +737 -0
- package/src/core/modules/better-auth/better-auth.config.ts +45 -15
- package/src/core/modules/better-auth/better-auth.middleware.ts +85 -2
- package/src/core/modules/better-auth/better-auth.module.ts +83 -27
- package/src/core/modules/better-auth/better-auth.resolver.ts +0 -11
- package/src/core/modules/better-auth/better-auth.service.ts +367 -12
- package/src/core/modules/better-auth/better-auth.types.ts +16 -0
- package/src/core/modules/better-auth/core-better-auth.controller.ts +44 -3
- package/src/core/modules/better-auth/core-better-auth.resolver.ts +136 -16
- package/src/core/modules/better-auth/index.ts +1 -0
- package/src/core/modules/user/core-user.service.ts +131 -4
- package/src/core/modules/user/interfaces/core-user-service-options.interface.ts +15 -0
- package/src/core.module.ts +264 -76
- package/src/index.ts +5 -0
- package/src/server/modules/auth/auth.resolver.ts +8 -0
- package/src/server/modules/better-auth/better-auth.module.ts +9 -3
- package/src/server/modules/better-auth/better-auth.resolver.ts +18 -11
- package/src/server/modules/user/user.controller.ts +1 -9
- 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.
|
|
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
|
-
|
|
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:
|
|
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
|
-
*
|
|
114
|
-
*
|
|
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
|
-
*
|
|
162
|
-
*
|
|
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
|
-
*
|
|
250
|
-
*
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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,
|
|
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.
|
|
44
|
-
@UseGuards(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|