@lenne.tech/nest-server 11.6.1 → 11.7.0
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 +132 -0
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/decorators/graphql-populate.decorator.d.ts +2 -2
- package/dist/core/common/decorators/restricted.decorator.d.ts +1 -0
- package/dist/core/common/decorators/restricted.decorator.js +1 -1
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/helpers/filter.helper.d.ts +9 -9
- package/dist/core/common/helpers/filter.helper.js +2 -4
- package/dist/core/common/helpers/filter.helper.js.map +1 -1
- package/dist/core/common/helpers/gridfs.helper.js +3 -3
- package/dist/core/common/helpers/gridfs.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +1 -0
- package/dist/core/common/helpers/input.helper.js +1 -1
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +51 -0
- package/dist/core/common/services/crud.service.d.ts +16 -16
- package/dist/core/common/services/crud.service.js +1 -1
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/modules/auth/auth-guard-strategy.enum.d.ts +1 -0
- package/dist/core/modules/auth/auth-guard-strategy.enum.js +1 -0
- package/dist/core/modules/auth/auth-guard-strategy.enum.js.map +1 -1
- package/dist/core/modules/auth/guards/auth.guard.js +11 -5
- package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
- package/dist/core/modules/auth/tokens.decorator.d.ts +1 -1
- package/dist/core/modules/better-auth/better-auth-auth.model.d.ts +9 -0
- package/dist/core/modules/better-auth/better-auth-auth.model.js +63 -0
- package/dist/core/modules/better-auth/better-auth-auth.model.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-models.d.ts +43 -0
- package/dist/core/modules/better-auth/better-auth-models.js +181 -0
- package/dist/core/modules/better-auth/better-auth-models.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.d.ts +12 -0
- package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.js +70 -0
- package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-rate-limiter.service.d.ts +32 -0
- package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js +173 -0
- package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.d.ts +43 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.js +159 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.config.d.ts +9 -0
- package/dist/core/modules/better-auth/better-auth.config.js +254 -0
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.middleware.d.ts +20 -0
- package/dist/core/modules/better-auth/better-auth.middleware.js +79 -0
- package/dist/core/modules/better-auth/better-auth.middleware.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.module.d.ts +38 -0
- package/dist/core/modules/better-auth/better-auth.module.js +253 -0
- package/dist/core/modules/better-auth/better-auth.module.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.resolver.d.ts +45 -0
- package/dist/core/modules/better-auth/better-auth.resolver.js +221 -0
- package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.service.d.ts +37 -0
- package/dist/core/modules/better-auth/better-auth.service.js +148 -0
- package/dist/core/modules/better-auth/better-auth.service.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth.types.d.ts +39 -0
- package/dist/core/modules/better-auth/better-auth.types.js +26 -0
- package/dist/core/modules/better-auth/better-auth.types.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +66 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js +491 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +59 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.js +538 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -0
- package/dist/core/modules/better-auth/index.d.ts +13 -0
- package/dist/core/modules/better-auth/index.js +30 -0
- package/dist/core/modules/better-auth/index.js.map +1 -0
- package/dist/core/modules/user/core-user.model.d.ts +2 -0
- package/dist/core/modules/user/core-user.model.js +21 -0
- package/dist/core/modules/user/core-user.model.js.map +1 -1
- package/dist/core.module.js +7 -0
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/better-auth/better-auth.controller.d.ts +10 -0
- package/dist/server/modules/better-auth/better-auth.controller.js +36 -0
- package/dist/server/modules/better-auth/better-auth.controller.js.map +1 -0
- package/dist/server/modules/better-auth/better-auth.module.d.ts +9 -0
- package/dist/server/modules/better-auth/better-auth.module.js +44 -0
- package/dist/server/modules/better-auth/better-auth.module.js.map +1 -0
- package/dist/server/modules/better-auth/better-auth.resolver.d.ts +45 -0
- package/dist/server/modules/better-auth/better-auth.resolver.js +221 -0
- package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -0
- package/dist/server/modules/file/file-info.model.d.ts +71 -3
- package/dist/server/modules/user/user.model.d.ts +169 -3
- package/dist/server/server.module.js +6 -1
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +21 -22
- package/src/config.env.ts +139 -1
- package/src/core/common/decorators/restricted.decorator.ts +2 -2
- package/src/core/common/helpers/filter.helper.ts +15 -17
- package/src/core/common/helpers/gridfs.helper.ts +5 -5
- package/src/core/common/helpers/input.helper.ts +2 -2
- package/src/core/common/interfaces/server-options.interface.ts +377 -20
- package/src/core/common/services/crud.service.ts +22 -22
- package/src/core/modules/auth/auth-guard-strategy.enum.ts +1 -0
- package/src/core/modules/auth/guards/auth.guard.ts +20 -6
- package/src/core/modules/better-auth/README.md +1422 -0
- package/src/core/modules/better-auth/better-auth-auth.model.ts +69 -0
- package/src/core/modules/better-auth/better-auth-models.ts +140 -0
- package/src/core/modules/better-auth/better-auth-rate-limit.middleware.ts +113 -0
- package/src/core/modules/better-auth/better-auth-rate-limiter.service.ts +326 -0
- package/src/core/modules/better-auth/better-auth-user.mapper.ts +269 -0
- package/src/core/modules/better-auth/better-auth.config.ts +488 -0
- package/src/core/modules/better-auth/better-auth.middleware.ts +111 -0
- package/src/core/modules/better-auth/better-auth.module.ts +474 -0
- package/src/core/modules/better-auth/better-auth.resolver.ts +213 -0
- package/src/core/modules/better-auth/better-auth.service.ts +314 -0
- package/src/core/modules/better-auth/better-auth.types.ts +90 -0
- package/src/core/modules/better-auth/core-better-auth.controller.ts +605 -0
- package/src/core/modules/better-auth/core-better-auth.resolver.ts +705 -0
- package/src/core/modules/better-auth/index.ts +32 -0
- package/src/core/modules/user/core-user.model.ts +29 -0
- package/src/core.module.ts +13 -0
- package/src/index.ts +6 -0
- package/src/server/modules/better-auth/better-auth.controller.ts +41 -0
- package/src/server/modules/better-auth/better-auth.module.ts +88 -0
- package/src/server/modules/better-auth/better-auth.resolver.ts +201 -0
- package/src/server/server.module.ts +10 -1
|
@@ -16,6 +16,357 @@ import { CronJobConfigWithTimeZone } from './cron-job-config-with-time-zone.inte
|
|
|
16
16
|
import { CronJobConfigWithUtcOffset } from './cron-job-config-with-utc-offset.interface';
|
|
17
17
|
import { MailjetOptions } from './mailjet-options.interface';
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Better-Auth field type definition
|
|
21
|
+
* Matches the DBFieldType from better-auth
|
|
22
|
+
*/
|
|
23
|
+
export type BetterAuthFieldType = 'boolean' | 'date' | 'json' | 'number' | 'number[]' | 'string' | 'string[]';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Interface for better-auth configuration
|
|
27
|
+
*/
|
|
28
|
+
export interface IBetterAuth {
|
|
29
|
+
/**
|
|
30
|
+
* Additional user fields beyond the core fields (firstName, lastName, etc.)
|
|
31
|
+
* These fields will be merged with the default user fields.
|
|
32
|
+
* @see https://www.better-auth.com/docs/concepts/users-accounts#additional-fields
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* additionalUserFields: {
|
|
36
|
+
* phoneNumber: { type: 'string', defaultValue: null },
|
|
37
|
+
* department: { type: 'string', required: true },
|
|
38
|
+
* preferences: { type: 'string', defaultValue: '{}' },
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
additionalUserFields?: Record<string, IBetterAuthUserField>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Whether BetterAuthModule should be auto-registered in CoreModule.
|
|
46
|
+
*
|
|
47
|
+
* When false (default), projects integrate BetterAuth via an extended module
|
|
48
|
+
* in their project (e.g., `src/server/modules/better-auth/better-auth.module.ts`).
|
|
49
|
+
* This follows the same pattern as Legacy Auth and allows for custom resolvers,
|
|
50
|
+
* controllers, and project-specific authentication logic.
|
|
51
|
+
*
|
|
52
|
+
* Set to true only for simple projects that don't need customization.
|
|
53
|
+
*
|
|
54
|
+
* @default false
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Recommended: Extend BetterAuthModule in your project
|
|
59
|
+
* // src/server/modules/better-auth/better-auth.module.ts
|
|
60
|
+
* import { BetterAuthModule as CoreBetterAuthModule } from '@lenne.tech/nest-server';
|
|
61
|
+
*
|
|
62
|
+
* @Module({})
|
|
63
|
+
* export class BetterAuthModule {
|
|
64
|
+
* static forRoot(options) {
|
|
65
|
+
* return {
|
|
66
|
+
* imports: [CoreBetterAuthModule.forRoot(options)],
|
|
67
|
+
* // Add custom providers, controllers, etc.
|
|
68
|
+
* };
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* // Then import in ServerModule
|
|
73
|
+
* import { BetterAuthModule } from './modules/better-auth/better-auth.module';
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
autoRegister?: boolean;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Base path for better-auth endpoints
|
|
80
|
+
* default: '/iam'
|
|
81
|
+
*/
|
|
82
|
+
basePath?: string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Base URL of the application
|
|
86
|
+
* e.g. 'http://localhost:3000'
|
|
87
|
+
*/
|
|
88
|
+
baseUrl?: string;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Email/password authentication configuration.
|
|
92
|
+
* Enabled by default.
|
|
93
|
+
* Set `enabled: false` to explicitly disable email/password auth.
|
|
94
|
+
*/
|
|
95
|
+
emailAndPassword?: {
|
|
96
|
+
/**
|
|
97
|
+
* Whether email/password authentication is enabled.
|
|
98
|
+
* @default true
|
|
99
|
+
*/
|
|
100
|
+
enabled?: boolean;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Whether better-auth is enabled.
|
|
105
|
+
* BetterAuth is enabled by default (zero-config philosophy).
|
|
106
|
+
* Set to false to explicitly disable it.
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
109
|
+
enabled?: boolean;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* JWT plugin configuration for API clients.
|
|
113
|
+
* Enabled by default when this config block is present.
|
|
114
|
+
* Set `enabled: false` to explicitly disable.
|
|
115
|
+
*/
|
|
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
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Advanced Better-Auth options passthrough.
|
|
132
|
+
* These options are passed directly to Better-Auth, allowing full customization.
|
|
133
|
+
* Use this for any Better-Auth options not explicitly defined in this interface.
|
|
134
|
+
* @see https://www.better-auth.com/docs/reference/options
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* options: {
|
|
138
|
+
* emailAndPassword: {
|
|
139
|
+
* enabled: true,
|
|
140
|
+
* requireEmailVerification: true,
|
|
141
|
+
* sendResetPassword: async ({ user, url }) => { ... },
|
|
142
|
+
* },
|
|
143
|
+
* account: {
|
|
144
|
+
* accountLinking: { enabled: true },
|
|
145
|
+
* },
|
|
146
|
+
* session: {
|
|
147
|
+
* expiresIn: 60 * 60 * 24 * 7, // 7 days
|
|
148
|
+
* updateAge: 60 * 60 * 24, // 1 day
|
|
149
|
+
* },
|
|
150
|
+
* advanced: {
|
|
151
|
+
* cookiePrefix: 'my-app',
|
|
152
|
+
* useSecureCookies: true,
|
|
153
|
+
* },
|
|
154
|
+
* }
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
options?: Record<string, unknown>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Passkey/WebAuthn configuration.
|
|
161
|
+
* Enabled by default when this config block is present.
|
|
162
|
+
* Set `enabled: false` to explicitly disable.
|
|
163
|
+
*/
|
|
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
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Additional Better-Auth plugins to include.
|
|
192
|
+
* These will be merged with the built-in plugins (jwt, twoFactor, passkey).
|
|
193
|
+
* @see https://www.better-auth.com/docs/plugins
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* import { organization } from 'better-auth/plugins';
|
|
197
|
+
* import { magicLink } from 'better-auth/plugins';
|
|
198
|
+
*
|
|
199
|
+
* plugins: [
|
|
200
|
+
* organization({ ... }),
|
|
201
|
+
* magicLink({ ... }),
|
|
202
|
+
* ]
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
plugins?: unknown[];
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Rate limiting configuration for Better-Auth endpoints
|
|
209
|
+
* Protects against brute-force attacks
|
|
210
|
+
*/
|
|
211
|
+
rateLimit?: IBetterAuthRateLimit;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Secret for better-auth (min 32 characters)
|
|
215
|
+
* Used for session encryption
|
|
216
|
+
*/
|
|
217
|
+
secret?: string;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Social login providers configuration
|
|
221
|
+
* Supports all Better-Auth providers dynamically (google, github, apple, discord, etc.)
|
|
222
|
+
*
|
|
223
|
+
* **Enabled by default:** Providers are automatically enabled when credentials
|
|
224
|
+
* are configured. Set `enabled: false` to explicitly disable a provider.
|
|
225
|
+
*
|
|
226
|
+
* @see https://www.better-auth.com/docs/authentication/social-sign-in
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* socialProviders: {
|
|
230
|
+
* // These providers are enabled (no need for enabled: true)
|
|
231
|
+
* google: { clientId: '...', clientSecret: '...' },
|
|
232
|
+
* github: { clientId: '...', clientSecret: '...' },
|
|
233
|
+
* // This provider is explicitly disabled
|
|
234
|
+
* discord: { clientId: '...', clientSecret: '...', enabled: false },
|
|
235
|
+
* }
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
socialProviders?: Record<string, IBetterAuthSocialProvider>;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Trusted origins for CORS and OAuth callbacks
|
|
242
|
+
* If not specified, defaults to [baseUrl]
|
|
243
|
+
* e.g. ['https://example.com', 'https://app.example.com']
|
|
244
|
+
*/
|
|
245
|
+
trustedOrigins?: string[];
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Two-factor authentication configuration.
|
|
249
|
+
* Enabled by default when this config block is present.
|
|
250
|
+
* Set `enabled: false` to explicitly disable.
|
|
251
|
+
*/
|
|
252
|
+
twoFactor?: {
|
|
253
|
+
/**
|
|
254
|
+
* App name shown in authenticator apps
|
|
255
|
+
* e.g. 'My Application'
|
|
256
|
+
*/
|
|
257
|
+
appName?: string;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Whether 2FA is enabled.
|
|
261
|
+
* @default true (when twoFactor config block is present)
|
|
262
|
+
*/
|
|
263
|
+
enabled?: boolean;
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Interface for Better-Auth rate limiting configuration
|
|
269
|
+
*/
|
|
270
|
+
export interface IBetterAuthRateLimit {
|
|
271
|
+
/**
|
|
272
|
+
* Whether rate limiting is enabled
|
|
273
|
+
* default: false
|
|
274
|
+
*/
|
|
275
|
+
enabled?: boolean;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Maximum number of requests within the time window
|
|
279
|
+
* default: 10
|
|
280
|
+
*/
|
|
281
|
+
max?: number;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Custom message when rate limit is exceeded
|
|
285
|
+
* default: 'Too many requests, please try again later.'
|
|
286
|
+
*/
|
|
287
|
+
message?: string;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Endpoints to skip rate limiting entirely
|
|
291
|
+
* e.g., ['/iam/session'] for session checks
|
|
292
|
+
*/
|
|
293
|
+
skipEndpoints?: string[];
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Endpoints to apply stricter rate limiting (e.g., sign-in, sign-up)
|
|
297
|
+
* These endpoints will have half the max requests
|
|
298
|
+
*/
|
|
299
|
+
strictEndpoints?: string[];
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Time window in seconds
|
|
303
|
+
* default: 60 (1 minute)
|
|
304
|
+
*/
|
|
305
|
+
windowSeconds?: number;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Interface for better-auth social provider configuration
|
|
310
|
+
*
|
|
311
|
+
* **Enabled by default:** A social provider is automatically enabled when
|
|
312
|
+
* both `clientId` and `clientSecret` are provided. You only need to set
|
|
313
|
+
* `enabled: false` to explicitly disable a configured provider.
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* // Provider is enabled (has credentials, no explicit enabled flag needed)
|
|
318
|
+
* google: { clientId: '...', clientSecret: '...' }
|
|
319
|
+
*
|
|
320
|
+
* // Provider is explicitly disabled despite having credentials
|
|
321
|
+
* github: { clientId: '...', clientSecret: '...', enabled: false }
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
export interface IBetterAuthSocialProvider {
|
|
325
|
+
/**
|
|
326
|
+
* OAuth client ID
|
|
327
|
+
*/
|
|
328
|
+
clientId: string;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* OAuth client secret
|
|
332
|
+
*/
|
|
333
|
+
clientSecret: string;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Whether this provider is enabled.
|
|
337
|
+
* Defaults to true when clientId and clientSecret are provided.
|
|
338
|
+
* Set to false to explicitly disable this provider.
|
|
339
|
+
* @default true (when credentials are configured)
|
|
340
|
+
*/
|
|
341
|
+
enabled?: boolean;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Interface for additional user fields in Better-Auth
|
|
346
|
+
* @see https://www.better-auth.com/docs/concepts/users-accounts#additional-fields
|
|
347
|
+
*/
|
|
348
|
+
export interface IBetterAuthUserField {
|
|
349
|
+
/**
|
|
350
|
+
* Default value for the field
|
|
351
|
+
*/
|
|
352
|
+
defaultValue?: unknown;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Database field name (if different from key)
|
|
356
|
+
*/
|
|
357
|
+
fieldName?: string;
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Whether this field is required
|
|
361
|
+
*/
|
|
362
|
+
required?: boolean;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Field type
|
|
366
|
+
*/
|
|
367
|
+
type: BetterAuthFieldType;
|
|
368
|
+
}
|
|
369
|
+
|
|
19
370
|
/**
|
|
20
371
|
* Interface for JWT configuration (main and refresh)
|
|
21
372
|
*/
|
|
@@ -71,6 +422,12 @@ export interface IServerOptions {
|
|
|
71
422
|
*/
|
|
72
423
|
automaticObjectIdFiltering?: boolean;
|
|
73
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Configuration for better-auth authentication framework
|
|
427
|
+
* See: https://better-auth.com
|
|
428
|
+
*/
|
|
429
|
+
betterAuth?: IBetterAuth;
|
|
430
|
+
|
|
74
431
|
/**
|
|
75
432
|
* Configuration for Brevo
|
|
76
433
|
* See: https://developers.brevo.com/
|
|
@@ -324,29 +681,29 @@ export interface IServerOptions {
|
|
|
324
681
|
* Hint: The secrets of the different environments should be different, otherwise a JWT can be used in different
|
|
325
682
|
* environments, which can lead to security vulnerabilities.
|
|
326
683
|
*/
|
|
327
|
-
jwt?: IJwt &
|
|
328
|
-
{
|
|
329
|
-
/**
|
|
330
|
-
* Configuration for refresh Token (JWT)
|
|
331
|
-
* Hint: The secret of the JWT and the Refresh Token should be different, otherwise a new RefreshToken can also be
|
|
332
|
-
* requested with the JWT, which can lead to a security vulnerability.
|
|
333
|
-
*/
|
|
334
|
-
refresh?: IJwt & {
|
|
684
|
+
jwt?: IJwt &
|
|
685
|
+
JwtModuleOptions & {
|
|
335
686
|
/**
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
687
|
+
* Configuration for refresh Token (JWT)
|
|
688
|
+
* Hint: The secret of the JWT and the Refresh Token should be different, otherwise a new RefreshToken can also be
|
|
689
|
+
* requested with the JWT, which can lead to a security vulnerability.
|
|
339
690
|
*/
|
|
340
|
-
|
|
341
|
-
|
|
691
|
+
refresh?: IJwt & {
|
|
692
|
+
/**
|
|
693
|
+
* Whether renewal of the refresh token is permitted
|
|
694
|
+
* If falsy (default): during refresh only a new token, the refresh token retains its original term
|
|
695
|
+
* If true: during refresh not only a new token but also a new refresh token is created
|
|
696
|
+
*/
|
|
697
|
+
renewal?: boolean;
|
|
698
|
+
};
|
|
342
699
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
700
|
+
/**
|
|
701
|
+
* Time period in milliseconds
|
|
702
|
+
* in which the same token ID is used so that all parallel token refresh requests of a device can be generated.
|
|
703
|
+
* default: 0 (every token includes a new token ID, all parallel token refresh requests must be prevented by the client or processed accordingly)
|
|
704
|
+
*/
|
|
705
|
+
sameTokenIdPeriod?: number;
|
|
706
|
+
};
|
|
350
707
|
|
|
351
708
|
/**
|
|
352
709
|
* Load local configuration
|
|
@@ -2,10 +2,10 @@ import { NotFoundException } from '@nestjs/common';
|
|
|
2
2
|
import {
|
|
3
3
|
AggregateOptions,
|
|
4
4
|
Document,
|
|
5
|
-
FilterQuery,
|
|
6
5
|
Model as MongooseModel,
|
|
7
6
|
PipelineStage,
|
|
8
7
|
Query,
|
|
8
|
+
QueryFilter,
|
|
9
9
|
QueryOptions,
|
|
10
10
|
} from 'mongoose';
|
|
11
11
|
|
|
@@ -147,7 +147,7 @@ export abstract class CrudService<
|
|
|
147
147
|
* Get items via filter
|
|
148
148
|
*/
|
|
149
149
|
async find(
|
|
150
|
-
filter?: FilterArgs | { filterQuery?:
|
|
150
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
151
151
|
serviceOptions?: ServiceOptions,
|
|
152
152
|
): Promise<Model[]> {
|
|
153
153
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
@@ -191,7 +191,7 @@ export abstract class CrudService<
|
|
|
191
191
|
* Warning: Disables the handling of rights and restrictions!
|
|
192
192
|
*/
|
|
193
193
|
async findForce(
|
|
194
|
-
filter?: FilterArgs | { filterQuery?:
|
|
194
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
195
195
|
serviceOptions: ServiceOptions = {},
|
|
196
196
|
): Promise<Model[]> {
|
|
197
197
|
serviceOptions = serviceOptions || {};
|
|
@@ -204,7 +204,7 @@ export abstract class CrudService<
|
|
|
204
204
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
205
205
|
*/
|
|
206
206
|
async findRaw(
|
|
207
|
-
filter?: FilterArgs | { filterQuery?:
|
|
207
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
208
208
|
serviceOptions: ServiceOptions = {},
|
|
209
209
|
): Promise<Model[]> {
|
|
210
210
|
serviceOptions = serviceOptions || {};
|
|
@@ -216,7 +216,7 @@ export abstract class CrudService<
|
|
|
216
216
|
* Get items and total count via filter
|
|
217
217
|
*/
|
|
218
218
|
async findAndCount(
|
|
219
|
-
filter?: FilterArgs | { filterQuery?:
|
|
219
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
220
220
|
serviceOptions?: ServiceOptions,
|
|
221
221
|
): Promise<{ items: Model[]; totalCount: number }> {
|
|
222
222
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
@@ -280,10 +280,10 @@ export abstract class CrudService<
|
|
|
280
280
|
|
|
281
281
|
// Find and process db items
|
|
282
282
|
const collation = serviceOptions?.collation || ConfigService.get('mongoose.collation');
|
|
283
|
-
const dbResult
|
|
284
|
-
|
|
283
|
+
const dbResult =
|
|
284
|
+
(await this.mainDbModel.aggregate(aggregation, collation ? { collation } : {}).exec())[0] || {};
|
|
285
285
|
dbResult.totalCount = dbResult.totalCount?.[0]?.total || 0;
|
|
286
|
-
dbResult.items = dbResult.items?.map(item => this.mainDbModel.hydrate(item)) || [];
|
|
286
|
+
dbResult.items = dbResult.items?.map((item) => this.mainDbModel.hydrate(item)) || [];
|
|
287
287
|
return dbResult;
|
|
288
288
|
},
|
|
289
289
|
{ input: filter, outputPath: 'items', serviceOptions },
|
|
@@ -295,7 +295,7 @@ export abstract class CrudService<
|
|
|
295
295
|
* Warning: Disables the handling of rights and restrictions!
|
|
296
296
|
*/
|
|
297
297
|
async findAndCountForce(
|
|
298
|
-
filter?: FilterArgs | { filterQuery?:
|
|
298
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
299
299
|
serviceOptions: ServiceOptions = {},
|
|
300
300
|
): Promise<{ items: Model[]; totalCount: number }> {
|
|
301
301
|
serviceOptions.raw = true;
|
|
@@ -307,7 +307,7 @@ export abstract class CrudService<
|
|
|
307
307
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
308
308
|
*/
|
|
309
309
|
async findAndCountRaw(
|
|
310
|
-
filter?: FilterArgs | { filterQuery?:
|
|
310
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
311
311
|
serviceOptions: ServiceOptions = {},
|
|
312
312
|
): Promise<{ items: Model[]; totalCount: number }> {
|
|
313
313
|
serviceOptions = serviceOptions || {};
|
|
@@ -319,7 +319,7 @@ export abstract class CrudService<
|
|
|
319
319
|
* Find and update
|
|
320
320
|
*/
|
|
321
321
|
async findAndUpdate(
|
|
322
|
-
filter: FilterArgs | { filterQuery?:
|
|
322
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
323
323
|
update: PlainObject<UpdateInput>,
|
|
324
324
|
serviceOptions?: ServiceOptions,
|
|
325
325
|
): Promise<Model[]> {
|
|
@@ -348,7 +348,7 @@ export abstract class CrudService<
|
|
|
348
348
|
* Warning: Disables the handling of rights and restrictions!
|
|
349
349
|
*/
|
|
350
350
|
async findAndUpdateForce(
|
|
351
|
-
filter: FilterArgs | { filterQuery?:
|
|
351
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
352
352
|
update: PlainObject<UpdateInput>,
|
|
353
353
|
serviceOptions: ServiceOptions = {},
|
|
354
354
|
): Promise<Model[]> {
|
|
@@ -362,7 +362,7 @@ export abstract class CrudService<
|
|
|
362
362
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
363
363
|
*/
|
|
364
364
|
async findAndUpdateRaw(
|
|
365
|
-
filter: FilterArgs | { filterQuery?:
|
|
365
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
366
366
|
update: PlainObject<UpdateInput>,
|
|
367
367
|
serviceOptions: ServiceOptions = {},
|
|
368
368
|
): Promise<Model[]> {
|
|
@@ -375,7 +375,7 @@ export abstract class CrudService<
|
|
|
375
375
|
* Find one item via filter
|
|
376
376
|
*/
|
|
377
377
|
async findOne(
|
|
378
|
-
filter?: FilterArgs | { filterQuery?:
|
|
378
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
379
379
|
serviceOptions?: ServiceOptions,
|
|
380
380
|
): Promise<Model> {
|
|
381
381
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
@@ -414,7 +414,7 @@ export abstract class CrudService<
|
|
|
414
414
|
* Warning: Disables the handling of rights and restrictions!
|
|
415
415
|
*/
|
|
416
416
|
async findOneForce(
|
|
417
|
-
filter?: FilterArgs | { filterQuery?:
|
|
417
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
418
418
|
serviceOptions: ServiceOptions = {},
|
|
419
419
|
): Promise<Model> {
|
|
420
420
|
serviceOptions = serviceOptions || {};
|
|
@@ -427,7 +427,7 @@ export abstract class CrudService<
|
|
|
427
427
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
428
428
|
*/
|
|
429
429
|
async findOneRaw(
|
|
430
|
-
filter?: FilterArgs | { filterQuery?:
|
|
430
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
431
431
|
serviceOptions: ServiceOptions = {},
|
|
432
432
|
): Promise<Model> {
|
|
433
433
|
serviceOptions = serviceOptions || {};
|
|
@@ -452,7 +452,7 @@ export abstract class CrudService<
|
|
|
452
452
|
* CRUD alias for find
|
|
453
453
|
*/
|
|
454
454
|
async read(
|
|
455
|
-
filter: FilterArgs | { filterQuery?:
|
|
455
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
456
456
|
serviceOptions?: ServiceOptions,
|
|
457
457
|
): Promise<Model[]>;
|
|
458
458
|
|
|
@@ -460,7 +460,7 @@ export abstract class CrudService<
|
|
|
460
460
|
* CRUD alias for get or find
|
|
461
461
|
*/
|
|
462
462
|
async read(
|
|
463
|
-
input: FilterArgs | string | { filterQuery?:
|
|
463
|
+
input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
464
464
|
serviceOptions?: ServiceOptions,
|
|
465
465
|
): Promise<Model | Model[]> {
|
|
466
466
|
if (typeof input === 'string') {
|
|
@@ -481,7 +481,7 @@ export abstract class CrudService<
|
|
|
481
481
|
* Warning: Disables the handling of rights and restrictions!
|
|
482
482
|
*/
|
|
483
483
|
async readForce(
|
|
484
|
-
filter: FilterArgs | { filterQuery?:
|
|
484
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
485
485
|
serviceOptions?: ServiceOptions,
|
|
486
486
|
): Promise<Model[]>;
|
|
487
487
|
|
|
@@ -490,7 +490,7 @@ export abstract class CrudService<
|
|
|
490
490
|
* Warning: Disables the handling of rights and restrictions!
|
|
491
491
|
*/
|
|
492
492
|
async readForce(
|
|
493
|
-
input: FilterArgs | string | { filterQuery?:
|
|
493
|
+
input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
494
494
|
serviceOptions?: ServiceOptions,
|
|
495
495
|
): Promise<Model | Model[]> {
|
|
496
496
|
if (typeof input === 'string') {
|
|
@@ -511,7 +511,7 @@ export abstract class CrudService<
|
|
|
511
511
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
512
512
|
*/
|
|
513
513
|
async readRaw(
|
|
514
|
-
filter: FilterArgs | { filterQuery?:
|
|
514
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
515
515
|
serviceOptions?: ServiceOptions,
|
|
516
516
|
): Promise<Model[]>;
|
|
517
517
|
|
|
@@ -520,7 +520,7 @@ export abstract class CrudService<
|
|
|
520
520
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
521
521
|
*/
|
|
522
522
|
async readRaw(
|
|
523
|
-
input: FilterArgs | string | { filterQuery?:
|
|
523
|
+
input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
524
524
|
serviceOptions?: ServiceOptions,
|
|
525
525
|
): Promise<Model | Model[]> {
|
|
526
526
|
if (typeof input === 'string') {
|
|
@@ -13,9 +13,9 @@ import { InvalidTokenException } from '../exceptions/invalid-token.exception';
|
|
|
13
13
|
/**
|
|
14
14
|
* Missing strategy error
|
|
15
15
|
*/
|
|
16
|
-
const NO_STRATEGY_ERROR
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const NO_STRATEGY_ERROR =
|
|
17
|
+
'In order to use "defaultStrategy", please, ensure to import PassportModule in each ' +
|
|
18
|
+
"place where AuthGuard() is being used. Otherwise, passport won't work correctly.";
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Interface for auth guard
|
|
@@ -38,7 +38,7 @@ const createPassportContext = (request, response) => (type, options, callback: (
|
|
|
38
38
|
} catch (err) {
|
|
39
39
|
reject(err);
|
|
40
40
|
}
|
|
41
|
-
})(request, response, err => (err ? reject(err) : resolve)),
|
|
41
|
+
})(request, response, (err) => (err ? reject(err) : resolve)),
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -70,8 +70,22 @@ function createAuthGuard(type?: AuthGuardStrategy | string | string[]): Type<IAu
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const options = { ...defaultOptions, ...this.options };
|
|
73
|
-
const response = context?.switchToHttp()?.getResponse();
|
|
74
73
|
const request = this.getRequest(context);
|
|
74
|
+
|
|
75
|
+
// Check if user is already authenticated via Better-Auth middleware
|
|
76
|
+
// Only skip Passport for Better-Auth users (marked with _authenticatedViaBetterAuth)
|
|
77
|
+
// This ensures JWT_REFRESH guard still validates refresh tokens properly
|
|
78
|
+
const existingUser = request?.[options.property || defaultOptions.property];
|
|
79
|
+
if (existingUser && existingUser._authenticatedViaBetterAuth === true) {
|
|
80
|
+
// User is authenticated via Better-Auth - skip Passport authentication
|
|
81
|
+
// Validate through handleRequest to ensure role checks work
|
|
82
|
+
const validatedUser = this.handleRequest(null, existingUser, null, context);
|
|
83
|
+
request[options.property || defaultOptions.property] = validatedUser;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Proceed with Passport authentication
|
|
88
|
+
const response = context?.switchToHttp()?.getResponse();
|
|
75
89
|
const passportFn = createPassportContext(request, response);
|
|
76
90
|
const user = await passportFn(type || this.options.defaultStrategy, options, (err, currentUser, info) =>
|
|
77
91
|
this.handleRequest(err, currentUser, info, context),
|
|
@@ -101,7 +115,7 @@ function createAuthGuard(type?: AuthGuardStrategy | string | string[]): Type<IAu
|
|
|
101
115
|
*/
|
|
102
116
|
async logIn<TRequest extends { logIn: (...params) => any } = any>(request: TRequest) {
|
|
103
117
|
const user = request[this.options.property || defaultOptions.property];
|
|
104
|
-
await new Promise<void>((resolve, reject) => request.logIn(user, err => (err ? reject(err) : resolve())));
|
|
118
|
+
await new Promise<void>((resolve, reject) => request.logIn(user, (err) => (err ? reject(err) : resolve())));
|
|
105
119
|
}
|
|
106
120
|
|
|
107
121
|
/**
|