@lenne.tech/nest-server 11.6.0 → 11.6.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 +141 -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/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/interceptors/check-security.interceptor.js +4 -3
- package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +50 -0
- 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 +44 -0
- package/dist/core/modules/better-auth/better-auth-models.js +185 -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 +251 -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 +30 -0
- package/dist/core/modules/better-auth/better-auth.module.js +265 -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 +49 -0
- package/dist/core/modules/better-auth/better-auth.resolver.js +539 -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 +38 -0
- package/dist/core/modules/better-auth/better-auth.service.js +151 -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 +38 -0
- package/dist/core/modules/better-auth/better-auth.types.js +15 -0
- package/dist/core/modules/better-auth/better-auth.types.js.map +1 -0
- package/dist/core/modules/better-auth/index.d.ts +11 -0
- package/dist/core/modules/better-auth/index.js +28 -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/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +9 -1
- package/src/config.env.ts +148 -1
- package/src/core/common/decorators/restricted.decorator.ts +2 -2
- package/src/core/common/helpers/input.helper.ts +2 -2
- package/src/core/common/interceptors/check-security.interceptor.ts +6 -5
- package/src/core/common/interfaces/server-options.interface.ts +344 -20
- 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 +1096 -0
- package/src/core/modules/better-auth/better-auth-auth.model.ts +69 -0
- package/src/core/modules/better-auth/better-auth-models.ts +143 -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 +483 -0
- package/src/core/modules/better-auth/better-auth.middleware.ts +111 -0
- package/src/core/modules/better-auth/better-auth.module.ts +433 -0
- package/src/core/modules/better-auth/better-auth.resolver.ts +678 -0
- package/src/core/modules/better-auth/better-auth.service.ts +323 -0
- package/src/core/modules/better-auth/better-auth.types.ts +75 -0
- package/src/core/modules/better-auth/index.ts +25 -0
- package/src/core/modules/user/core-user.model.ts +29 -0
- package/src/core.module.ts +12 -0
- package/src/index.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.6.
|
|
3
|
+
"version": "11.6.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",
|
|
@@ -77,6 +77,8 @@
|
|
|
77
77
|
"node": ">= 20"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
+
"@apollo/server": "4.12.2",
|
|
81
|
+
"@better-auth/passkey": "1.4.7",
|
|
80
82
|
"@getbrevo/brevo": "3.0.1",
|
|
81
83
|
"@nestjs/apollo": "13.1.0",
|
|
82
84
|
"@nestjs/common": "11.1.9",
|
|
@@ -89,8 +91,11 @@
|
|
|
89
91
|
"@nestjs/schedule": "6.1.0",
|
|
90
92
|
"@nestjs/swagger": "11.2.3",
|
|
91
93
|
"@nestjs/terminus": "11.0.0",
|
|
94
|
+
"@nestjs/websockets": "11.1.9",
|
|
95
|
+
"@thallesp/nestjs-better-auth": "2.2.0",
|
|
92
96
|
"apollo-server-core": "3.13.0",
|
|
93
97
|
"bcrypt": "6.0.0",
|
|
98
|
+
"better-auth": "1.4.7",
|
|
94
99
|
"class-transformer": "0.5.1",
|
|
95
100
|
"class-validator": "0.14.3",
|
|
96
101
|
"compression": "1.8.1",
|
|
@@ -174,6 +179,9 @@
|
|
|
174
179
|
"flat": "5.0.2",
|
|
175
180
|
"mime": "2.6.0"
|
|
176
181
|
},
|
|
182
|
+
"better-auth": {
|
|
183
|
+
"mongodb": "7.0.0"
|
|
184
|
+
},
|
|
177
185
|
"ts-morph": "27.0.2"
|
|
178
186
|
},
|
|
179
187
|
"jest": {
|
package/src/config.env.ts
CHANGED
|
@@ -15,6 +15,54 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
15
15
|
// ===========================================================================
|
|
16
16
|
development: {
|
|
17
17
|
automaticObjectIdFiltering: true,
|
|
18
|
+
betterAuth: {
|
|
19
|
+
basePath: '/iam',
|
|
20
|
+
baseUrl: 'http://localhost:3000',
|
|
21
|
+
// enabled: true by default - set false to explicitly disable
|
|
22
|
+
jwt: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
expiresIn: '15m',
|
|
25
|
+
},
|
|
26
|
+
legacyPassword: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
},
|
|
29
|
+
passkey: {
|
|
30
|
+
enabled: false,
|
|
31
|
+
origin: 'http://localhost:3000',
|
|
32
|
+
rpId: 'localhost',
|
|
33
|
+
rpName: 'Nest Server Development',
|
|
34
|
+
},
|
|
35
|
+
rateLimit: {
|
|
36
|
+
enabled: true,
|
|
37
|
+
max: 20,
|
|
38
|
+
message: 'Too many requests, please try again later.',
|
|
39
|
+
skipEndpoints: ['/session', '/callback'],
|
|
40
|
+
strictEndpoints: ['/sign-in', '/sign-up', '/forgot-password', '/reset-password'],
|
|
41
|
+
windowSeconds: 60,
|
|
42
|
+
},
|
|
43
|
+
secret: 'BETTER_AUTH_SECRET_DEV_32_CHARS_MIN',
|
|
44
|
+
socialProviders: {
|
|
45
|
+
apple: {
|
|
46
|
+
clientId: process.env.SOCIAL_APPLE_CLIENT_ID || '',
|
|
47
|
+
clientSecret: process.env.SOCIAL_APPLE_CLIENT_SECRET || '',
|
|
48
|
+
enabled: false,
|
|
49
|
+
},
|
|
50
|
+
github: {
|
|
51
|
+
clientId: process.env.SOCIAL_GITHUB_CLIENT_ID || '',
|
|
52
|
+
clientSecret: process.env.SOCIAL_GITHUB_CLIENT_SECRET || '',
|
|
53
|
+
enabled: false,
|
|
54
|
+
},
|
|
55
|
+
google: {
|
|
56
|
+
clientId: process.env.SOCIAL_GOOGLE_CLIENT_ID || '',
|
|
57
|
+
clientSecret: process.env.SOCIAL_GOOGLE_CLIENT_SECRET || '',
|
|
58
|
+
enabled: false,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
twoFactor: {
|
|
62
|
+
appName: 'Nest Server Development',
|
|
63
|
+
enabled: false,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
18
66
|
compression: true,
|
|
19
67
|
cookies: false,
|
|
20
68
|
email: {
|
|
@@ -114,10 +162,58 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
114
162
|
},
|
|
115
163
|
|
|
116
164
|
// ===========================================================================
|
|
117
|
-
//
|
|
165
|
+
// Local environment
|
|
118
166
|
// ===========================================================================
|
|
119
167
|
local: {
|
|
120
168
|
automaticObjectIdFiltering: true,
|
|
169
|
+
betterAuth: {
|
|
170
|
+
basePath: '/iam',
|
|
171
|
+
baseUrl: 'http://localhost:3000',
|
|
172
|
+
// enabled: true by default - set false to explicitly disable
|
|
173
|
+
jwt: {
|
|
174
|
+
enabled: true,
|
|
175
|
+
expiresIn: '15m',
|
|
176
|
+
},
|
|
177
|
+
legacyPassword: {
|
|
178
|
+
enabled: true,
|
|
179
|
+
},
|
|
180
|
+
passkey: {
|
|
181
|
+
enabled: false,
|
|
182
|
+
origin: 'http://localhost:3000',
|
|
183
|
+
rpId: 'localhost',
|
|
184
|
+
rpName: 'Nest Server Local',
|
|
185
|
+
},
|
|
186
|
+
rateLimit: {
|
|
187
|
+
enabled: true,
|
|
188
|
+
max: 20,
|
|
189
|
+
message: 'Too many requests, please try again later.',
|
|
190
|
+
skipEndpoints: ['/session', '/callback'],
|
|
191
|
+
strictEndpoints: ['/sign-in', '/sign-up', '/forgot-password', '/reset-password'],
|
|
192
|
+
windowSeconds: 60,
|
|
193
|
+
},
|
|
194
|
+
secret: 'BETTER_AUTH_SECRET_LOCAL_32_CHARS_M',
|
|
195
|
+
socialProviders: {
|
|
196
|
+
apple: {
|
|
197
|
+
clientId: process.env.SOCIAL_APPLE_CLIENT_ID || '',
|
|
198
|
+
clientSecret: process.env.SOCIAL_APPLE_CLIENT_SECRET || '',
|
|
199
|
+
enabled: false,
|
|
200
|
+
},
|
|
201
|
+
github: {
|
|
202
|
+
clientId: process.env.SOCIAL_GITHUB_CLIENT_ID || '',
|
|
203
|
+
clientSecret: process.env.SOCIAL_GITHUB_CLIENT_SECRET || '',
|
|
204
|
+
enabled: false,
|
|
205
|
+
},
|
|
206
|
+
google: {
|
|
207
|
+
clientId: process.env.SOCIAL_GOOGLE_CLIENT_ID || '',
|
|
208
|
+
clientSecret: process.env.SOCIAL_GOOGLE_CLIENT_SECRET || '',
|
|
209
|
+
enabled: false,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
twoFactor: {
|
|
213
|
+
appName: 'Nest Server Local',
|
|
214
|
+
enabled: false,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
121
217
|
compression: true,
|
|
122
218
|
cookies: false,
|
|
123
219
|
cronJobs: {
|
|
@@ -232,6 +328,57 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
232
328
|
// ===========================================================================
|
|
233
329
|
production: {
|
|
234
330
|
automaticObjectIdFiltering: true,
|
|
331
|
+
betterAuth: {
|
|
332
|
+
basePath: '/iam',
|
|
333
|
+
baseUrl: process.env.BETTER_AUTH_URL || 'https://example.com',
|
|
334
|
+
// enabled: true by default - set false to explicitly disable
|
|
335
|
+
jwt: {
|
|
336
|
+
enabled: true,
|
|
337
|
+
expiresIn: '15m',
|
|
338
|
+
},
|
|
339
|
+
legacyPassword: {
|
|
340
|
+
enabled: true,
|
|
341
|
+
},
|
|
342
|
+
passkey: {
|
|
343
|
+
enabled: false,
|
|
344
|
+
origin: process.env.BETTER_AUTH_URL || 'https://example.com',
|
|
345
|
+
rpId: process.env.PASSKEY_RP_ID || 'example.com',
|
|
346
|
+
rpName: process.env.PASSKEY_RP_NAME || 'Nest Server Production',
|
|
347
|
+
},
|
|
348
|
+
rateLimit: {
|
|
349
|
+
enabled: process.env.RATE_LIMIT_ENABLED !== 'false',
|
|
350
|
+
max: parseInt(process.env.RATE_LIMIT_MAX || '10', 10),
|
|
351
|
+
message: process.env.RATE_LIMIT_MESSAGE || 'Too many requests, please try again later.',
|
|
352
|
+
skipEndpoints: ['/session', '/callback'],
|
|
353
|
+
strictEndpoints: ['/sign-in', '/sign-up', '/forgot-password', '/reset-password'],
|
|
354
|
+
windowSeconds: parseInt(process.env.RATE_LIMIT_WINDOW_SECONDS || '60', 10),
|
|
355
|
+
},
|
|
356
|
+
// IMPORTANT: Set BETTER_AUTH_SECRET in production!
|
|
357
|
+
// Without it, an insecure default is used which allows session forgery.
|
|
358
|
+
// Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
|
|
359
|
+
secret: process.env.BETTER_AUTH_SECRET,
|
|
360
|
+
socialProviders: {
|
|
361
|
+
apple: {
|
|
362
|
+
clientId: process.env.SOCIAL_APPLE_CLIENT_ID || '',
|
|
363
|
+
clientSecret: process.env.SOCIAL_APPLE_CLIENT_SECRET || '',
|
|
364
|
+
enabled: !!process.env.SOCIAL_APPLE_CLIENT_ID,
|
|
365
|
+
},
|
|
366
|
+
github: {
|
|
367
|
+
clientId: process.env.SOCIAL_GITHUB_CLIENT_ID || '',
|
|
368
|
+
clientSecret: process.env.SOCIAL_GITHUB_CLIENT_SECRET || '',
|
|
369
|
+
enabled: !!process.env.SOCIAL_GITHUB_CLIENT_ID,
|
|
370
|
+
},
|
|
371
|
+
google: {
|
|
372
|
+
clientId: process.env.SOCIAL_GOOGLE_CLIENT_ID || '',
|
|
373
|
+
clientSecret: process.env.SOCIAL_GOOGLE_CLIENT_SECRET || '',
|
|
374
|
+
enabled: !!process.env.SOCIAL_GOOGLE_CLIENT_ID,
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
twoFactor: {
|
|
378
|
+
appName: process.env.TWO_FACTOR_APP_NAME || 'Nest Server',
|
|
379
|
+
enabled: process.env.TWO_FACTOR_ENABLED === 'true',
|
|
380
|
+
},
|
|
381
|
+
},
|
|
235
382
|
compression: true,
|
|
236
383
|
cookies: false,
|
|
237
384
|
email: {
|
|
@@ -61,7 +61,7 @@ export const getRestricted = (object: unknown, propertyKey?: string): Restricted
|
|
|
61
61
|
*/
|
|
62
62
|
export const checkRestricted = (
|
|
63
63
|
data: any,
|
|
64
|
-
user: { hasRole: (roles: string[]) => boolean; id: any; verified?: any; verifiedAt?: any },
|
|
64
|
+
user: { emailVerified?: any; hasRole: (roles: string[]) => boolean; id: any; verified?: any; verifiedAt?: any },
|
|
65
65
|
options: {
|
|
66
66
|
allowCreatorOfParent?: boolean;
|
|
67
67
|
checkObjectItself?: boolean;
|
|
@@ -163,7 +163,7 @@ export const checkRestricted = (
|
|
|
163
163
|
(roles.includes(RoleEnum.S_CREATOR) &&
|
|
164
164
|
(('createdBy' in data && equalIds(data.createdBy, user)) ||
|
|
165
165
|
(config.allowCreatorOfParent && !('createdBy' in data) && config.isCreatorOfParent))) ||
|
|
166
|
-
(roles.includes(RoleEnum.S_VERIFIED) && (user?.verified || user?.verifiedAt))
|
|
166
|
+
(roles.includes(RoleEnum.S_VERIFIED) && (user?.verified || user?.verifiedAt || user?.emailVerified))
|
|
167
167
|
) {
|
|
168
168
|
valid = true;
|
|
169
169
|
}
|
|
@@ -209,7 +209,7 @@ export function assignPlain(target: Record<any, any>, ...args: Record<any, any>[
|
|
|
209
209
|
*/
|
|
210
210
|
export async function check(
|
|
211
211
|
value: any,
|
|
212
|
-
user: { hasRole: (roles: string[]) => boolean; id: any; verified?: any; verifiedAt?: any },
|
|
212
|
+
user: { emailVerified?: any; hasRole: (roles: string[]) => boolean; id: any; verified?: any; verifiedAt?: any },
|
|
213
213
|
options?: {
|
|
214
214
|
allowCreatorOfParent?: boolean;
|
|
215
215
|
dbObject?: any;
|
|
@@ -264,7 +264,7 @@ export async function check(
|
|
|
264
264
|
!('createdBy' in config.dbObject) &&
|
|
265
265
|
config.isCreatorOfParent))) ||
|
|
266
266
|
// check if the is verified
|
|
267
|
-
(roles.includes(RoleEnum.S_VERIFIED) && (user?.verified || user?.verifiedAt))
|
|
267
|
+
(roles.includes(RoleEnum.S_VERIFIED) && (user?.verified || user?.verifiedAt || user?.emailVerified))
|
|
268
268
|
) {
|
|
269
269
|
valid = true;
|
|
270
270
|
}
|
|
@@ -31,12 +31,13 @@ export class CheckSecurityInterceptor implements NestInterceptor {
|
|
|
31
31
|
// Get current user
|
|
32
32
|
const user = getContextData(context)?.currentUser || null;
|
|
33
33
|
|
|
34
|
-
// Set force mode for sign in and sign up
|
|
34
|
+
// Set force mode for sign in and sign up (both GraphQL and REST)
|
|
35
35
|
let force = false;
|
|
36
36
|
if (!user) {
|
|
37
37
|
// Here the name is used and not the class itself, because the concrete class is located in the respective project.
|
|
38
|
-
// In case of an override it is better to use the concrete class directly (context.getClass() instead of context.
|
|
39
|
-
|
|
38
|
+
// In case of an override it is better to use the concrete class directly (context.getClass() instead of context.getClass()?.name).
|
|
39
|
+
const className = context.getClass()?.name;
|
|
40
|
+
if (className === 'AuthResolver' || className === 'AuthController') {
|
|
40
41
|
force = true;
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -76,7 +77,7 @@ export class CheckSecurityInterceptor implements NestInterceptor {
|
|
|
76
77
|
|
|
77
78
|
// Check if data is writeable (e.g. objects from direct access to json files via http are not writable)
|
|
78
79
|
if (data && typeof data === 'object') {
|
|
79
|
-
const writeable = !Object.keys(data).find(key => !Object.getOwnPropertyDescriptor(data, key).writable);
|
|
80
|
+
const writeable = !Object.keys(data).find((key) => !Object.getOwnPropertyDescriptor(data, key).writable);
|
|
80
81
|
if (!writeable) {
|
|
81
82
|
return data;
|
|
82
83
|
}
|
|
@@ -88,7 +89,7 @@ export class CheckSecurityInterceptor implements NestInterceptor {
|
|
|
88
89
|
(item) => {
|
|
89
90
|
if (!item || typeof item !== 'object' || typeof item.securityCheck !== 'function') {
|
|
90
91
|
if (Array.isArray(item)) {
|
|
91
|
-
return item.filter(i => i !== undefined);
|
|
92
|
+
return item.filter((i) => i !== undefined);
|
|
92
93
|
}
|
|
93
94
|
return item;
|
|
94
95
|
}
|
|
@@ -16,6 +16,324 @@ 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
|
+
* Base path for better-auth endpoints
|
|
46
|
+
* default: '/iam'
|
|
47
|
+
*/
|
|
48
|
+
basePath?: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Base URL of the application
|
|
52
|
+
* e.g. 'http://localhost:3000'
|
|
53
|
+
*/
|
|
54
|
+
baseUrl?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Whether better-auth is enabled.
|
|
58
|
+
* BetterAuth is enabled by default (zero-config philosophy).
|
|
59
|
+
* Set to false to explicitly disable it.
|
|
60
|
+
* @default true
|
|
61
|
+
*/
|
|
62
|
+
enabled?: boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* JWT plugin configuration for API clients.
|
|
66
|
+
* Enabled by default when this config block is present.
|
|
67
|
+
* Set `enabled: false` to explicitly disable.
|
|
68
|
+
*/
|
|
69
|
+
jwt?: {
|
|
70
|
+
/**
|
|
71
|
+
* Whether JWT plugin is enabled.
|
|
72
|
+
* @default true (when jwt config block is present)
|
|
73
|
+
*/
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* JWT expiration time
|
|
78
|
+
* @default '15m'
|
|
79
|
+
*/
|
|
80
|
+
expiresIn?: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Legacy password handling configuration.
|
|
85
|
+
* Used during migration from old auth system.
|
|
86
|
+
* Enabled by default when this config block is present.
|
|
87
|
+
* Set `enabled: false` to explicitly disable.
|
|
88
|
+
*/
|
|
89
|
+
legacyPassword?: {
|
|
90
|
+
/**
|
|
91
|
+
* Whether legacy password handling is enabled.
|
|
92
|
+
* @default true (when legacyPassword config block is present)
|
|
93
|
+
*/
|
|
94
|
+
enabled?: boolean;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Advanced Better-Auth options passthrough.
|
|
99
|
+
* These options are passed directly to Better-Auth, allowing full customization.
|
|
100
|
+
* Use this for any Better-Auth options not explicitly defined in this interface.
|
|
101
|
+
* @see https://www.better-auth.com/docs/reference/options
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* options: {
|
|
105
|
+
* emailAndPassword: {
|
|
106
|
+
* enabled: true,
|
|
107
|
+
* requireEmailVerification: true,
|
|
108
|
+
* sendResetPassword: async ({ user, url }) => { ... },
|
|
109
|
+
* },
|
|
110
|
+
* account: {
|
|
111
|
+
* accountLinking: { enabled: true },
|
|
112
|
+
* },
|
|
113
|
+
* session: {
|
|
114
|
+
* expiresIn: 60 * 60 * 24 * 7, // 7 days
|
|
115
|
+
* updateAge: 60 * 60 * 24, // 1 day
|
|
116
|
+
* },
|
|
117
|
+
* advanced: {
|
|
118
|
+
* cookiePrefix: 'my-app',
|
|
119
|
+
* useSecureCookies: true,
|
|
120
|
+
* },
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
options?: Record<string, unknown>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Passkey/WebAuthn configuration.
|
|
128
|
+
* Enabled by default when this config block is present.
|
|
129
|
+
* Set `enabled: false` to explicitly disable.
|
|
130
|
+
*/
|
|
131
|
+
passkey?: {
|
|
132
|
+
/**
|
|
133
|
+
* Whether passkey authentication is enabled.
|
|
134
|
+
* @default true (when passkey config block is present)
|
|
135
|
+
*/
|
|
136
|
+
enabled?: boolean;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Origin URL for WebAuthn
|
|
140
|
+
* e.g. 'http://localhost:3000'
|
|
141
|
+
*/
|
|
142
|
+
origin?: string;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Relying Party ID (usually the domain)
|
|
146
|
+
* e.g. 'localhost' or 'example.com'
|
|
147
|
+
*/
|
|
148
|
+
rpId?: string;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Relying Party Name (displayed to users)
|
|
152
|
+
* e.g. 'My Application'
|
|
153
|
+
*/
|
|
154
|
+
rpName?: string;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Additional Better-Auth plugins to include.
|
|
159
|
+
* These will be merged with the built-in plugins (jwt, twoFactor, passkey).
|
|
160
|
+
* @see https://www.better-auth.com/docs/plugins
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* import { organization } from 'better-auth/plugins';
|
|
164
|
+
* import { magicLink } from 'better-auth/plugins';
|
|
165
|
+
*
|
|
166
|
+
* plugins: [
|
|
167
|
+
* organization({ ... }),
|
|
168
|
+
* magicLink({ ... }),
|
|
169
|
+
* ]
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
plugins?: unknown[];
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Rate limiting configuration for Better-Auth endpoints
|
|
176
|
+
* Protects against brute-force attacks
|
|
177
|
+
*/
|
|
178
|
+
rateLimit?: IBetterAuthRateLimit;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Secret for better-auth (min 32 characters)
|
|
182
|
+
* Used for session encryption
|
|
183
|
+
*/
|
|
184
|
+
secret?: string;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Social login providers configuration
|
|
188
|
+
* Supports all Better-Auth providers dynamically (google, github, apple, discord, etc.)
|
|
189
|
+
*
|
|
190
|
+
* **Enabled by default:** Providers are automatically enabled when credentials
|
|
191
|
+
* are configured. Set `enabled: false` to explicitly disable a provider.
|
|
192
|
+
*
|
|
193
|
+
* @see https://www.better-auth.com/docs/authentication/social-sign-in
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* socialProviders: {
|
|
197
|
+
* // These providers are enabled (no need for enabled: true)
|
|
198
|
+
* google: { clientId: '...', clientSecret: '...' },
|
|
199
|
+
* github: { clientId: '...', clientSecret: '...' },
|
|
200
|
+
* // This provider is explicitly disabled
|
|
201
|
+
* discord: { clientId: '...', clientSecret: '...', enabled: false },
|
|
202
|
+
* }
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
socialProviders?: Record<string, IBetterAuthSocialProvider>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Trusted origins for CORS and OAuth callbacks
|
|
209
|
+
* If not specified, defaults to [baseUrl]
|
|
210
|
+
* e.g. ['https://example.com', 'https://app.example.com']
|
|
211
|
+
*/
|
|
212
|
+
trustedOrigins?: string[];
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Two-factor authentication configuration.
|
|
216
|
+
* Enabled by default when this config block is present.
|
|
217
|
+
* Set `enabled: false` to explicitly disable.
|
|
218
|
+
*/
|
|
219
|
+
twoFactor?: {
|
|
220
|
+
/**
|
|
221
|
+
* App name shown in authenticator apps
|
|
222
|
+
* e.g. 'My Application'
|
|
223
|
+
*/
|
|
224
|
+
appName?: string;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Whether 2FA is enabled.
|
|
228
|
+
* @default true (when twoFactor config block is present)
|
|
229
|
+
*/
|
|
230
|
+
enabled?: boolean;
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Interface for Better-Auth rate limiting configuration
|
|
236
|
+
*/
|
|
237
|
+
export interface IBetterAuthRateLimit {
|
|
238
|
+
/**
|
|
239
|
+
* Whether rate limiting is enabled
|
|
240
|
+
* default: false
|
|
241
|
+
*/
|
|
242
|
+
enabled?: boolean;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Maximum number of requests within the time window
|
|
246
|
+
* default: 10
|
|
247
|
+
*/
|
|
248
|
+
max?: number;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Custom message when rate limit is exceeded
|
|
252
|
+
* default: 'Too many requests, please try again later.'
|
|
253
|
+
*/
|
|
254
|
+
message?: string;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Endpoints to skip rate limiting entirely
|
|
258
|
+
* e.g., ['/iam/session'] for session checks
|
|
259
|
+
*/
|
|
260
|
+
skipEndpoints?: string[];
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Endpoints to apply stricter rate limiting (e.g., sign-in, sign-up)
|
|
264
|
+
* These endpoints will have half the max requests
|
|
265
|
+
*/
|
|
266
|
+
strictEndpoints?: string[];
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Time window in seconds
|
|
270
|
+
* default: 60 (1 minute)
|
|
271
|
+
*/
|
|
272
|
+
windowSeconds?: number;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Interface for better-auth social provider configuration
|
|
277
|
+
*
|
|
278
|
+
* **Enabled by default:** A social provider is automatically enabled when
|
|
279
|
+
* both `clientId` and `clientSecret` are provided. You only need to set
|
|
280
|
+
* `enabled: false` to explicitly disable a configured provider.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* // Provider is enabled (has credentials, no explicit enabled flag needed)
|
|
285
|
+
* google: { clientId: '...', clientSecret: '...' }
|
|
286
|
+
*
|
|
287
|
+
* // Provider is explicitly disabled despite having credentials
|
|
288
|
+
* github: { clientId: '...', clientSecret: '...', enabled: false }
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
export interface IBetterAuthSocialProvider {
|
|
292
|
+
/**
|
|
293
|
+
* OAuth client ID
|
|
294
|
+
*/
|
|
295
|
+
clientId: string;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* OAuth client secret
|
|
299
|
+
*/
|
|
300
|
+
clientSecret: string;
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Whether this provider is enabled.
|
|
304
|
+
* Defaults to true when clientId and clientSecret are provided.
|
|
305
|
+
* Set to false to explicitly disable this provider.
|
|
306
|
+
* @default true (when credentials are configured)
|
|
307
|
+
*/
|
|
308
|
+
enabled?: boolean;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Interface for additional user fields in Better-Auth
|
|
313
|
+
* @see https://www.better-auth.com/docs/concepts/users-accounts#additional-fields
|
|
314
|
+
*/
|
|
315
|
+
export interface IBetterAuthUserField {
|
|
316
|
+
/**
|
|
317
|
+
* Default value for the field
|
|
318
|
+
*/
|
|
319
|
+
defaultValue?: unknown;
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Database field name (if different from key)
|
|
323
|
+
*/
|
|
324
|
+
fieldName?: string;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Whether this field is required
|
|
328
|
+
*/
|
|
329
|
+
required?: boolean;
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Field type
|
|
333
|
+
*/
|
|
334
|
+
type: BetterAuthFieldType;
|
|
335
|
+
}
|
|
336
|
+
|
|
19
337
|
/**
|
|
20
338
|
* Interface for JWT configuration (main and refresh)
|
|
21
339
|
*/
|
|
@@ -71,6 +389,12 @@ export interface IServerOptions {
|
|
|
71
389
|
*/
|
|
72
390
|
automaticObjectIdFiltering?: boolean;
|
|
73
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Configuration for better-auth authentication framework
|
|
394
|
+
* See: https://better-auth.com
|
|
395
|
+
*/
|
|
396
|
+
betterAuth?: IBetterAuth;
|
|
397
|
+
|
|
74
398
|
/**
|
|
75
399
|
* Configuration for Brevo
|
|
76
400
|
* See: https://developers.brevo.com/
|
|
@@ -324,29 +648,29 @@ export interface IServerOptions {
|
|
|
324
648
|
* Hint: The secrets of the different environments should be different, otherwise a JWT can be used in different
|
|
325
649
|
* environments, which can lead to security vulnerabilities.
|
|
326
650
|
*/
|
|
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 & {
|
|
651
|
+
jwt?: IJwt &
|
|
652
|
+
JwtModuleOptions & {
|
|
335
653
|
/**
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
654
|
+
* Configuration for refresh Token (JWT)
|
|
655
|
+
* Hint: The secret of the JWT and the Refresh Token should be different, otherwise a new RefreshToken can also be
|
|
656
|
+
* requested with the JWT, which can lead to a security vulnerability.
|
|
339
657
|
*/
|
|
340
|
-
|
|
341
|
-
|
|
658
|
+
refresh?: IJwt & {
|
|
659
|
+
/**
|
|
660
|
+
* Whether renewal of the refresh token is permitted
|
|
661
|
+
* If falsy (default): during refresh only a new token, the refresh token retains its original term
|
|
662
|
+
* If true: during refresh not only a new token but also a new refresh token is created
|
|
663
|
+
*/
|
|
664
|
+
renewal?: boolean;
|
|
665
|
+
};
|
|
342
666
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
667
|
+
/**
|
|
668
|
+
* Time period in milliseconds
|
|
669
|
+
* in which the same token ID is used so that all parallel token refresh requests of a device can be generated.
|
|
670
|
+
* default: 0 (every token includes a new token ID, all parallel token refresh requests must be prevented by the client or processed accordingly)
|
|
671
|
+
*/
|
|
672
|
+
sameTokenIdPeriod?: number;
|
|
673
|
+
};
|
|
350
674
|
|
|
351
675
|
/**
|
|
352
676
|
* Load local configuration
|