@lenne.tech/nest-server 11.7.0 → 11.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/config.env.js +17 -1
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/interfaces/server-options.interface.d.ts +35 -15
  4. package/dist/core/modules/auth/core-auth.controller.d.ts +1 -0
  5. package/dist/core/modules/auth/core-auth.controller.js +29 -3
  6. package/dist/core/modules/auth/core-auth.controller.js.map +1 -1
  7. package/dist/core/modules/auth/core-auth.module.js +14 -1
  8. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  9. package/dist/core/modules/auth/core-auth.resolver.d.ts +1 -0
  10. package/dist/core/modules/auth/core-auth.resolver.js +21 -3
  11. package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
  12. package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.d.ts +4 -0
  13. package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js +17 -0
  14. package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js.map +1 -0
  15. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.d.ts +9 -0
  16. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +74 -0
  17. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -0
  18. package/dist/core/modules/auth/interfaces/auth-provider.interface.d.ts +7 -0
  19. package/dist/core/modules/auth/interfaces/auth-provider.interface.js +5 -0
  20. package/dist/core/modules/auth/interfaces/auth-provider.interface.js.map +1 -0
  21. package/dist/core/modules/auth/interfaces/core-auth-user.interface.d.ts +1 -0
  22. package/dist/core/modules/auth/services/core-auth.service.d.ts +10 -1
  23. package/dist/core/modules/auth/services/core-auth.service.js +141 -9
  24. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  25. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.d.ts +31 -0
  26. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +153 -0
  27. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -0
  28. package/dist/core/modules/better-auth/better-auth-migration-status.model.d.ts +10 -0
  29. package/dist/core/modules/better-auth/better-auth-migration-status.model.js +57 -0
  30. package/dist/core/modules/better-auth/better-auth-migration-status.model.js.map +1 -0
  31. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js +1 -1
  32. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +1 -1
  33. package/dist/core/modules/better-auth/better-auth-user.mapper.d.ts +33 -0
  34. package/dist/core/modules/better-auth/better-auth-user.mapper.js +395 -0
  35. package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -1
  36. package/dist/core/modules/better-auth/better-auth.config.js +29 -10
  37. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  38. package/dist/core/modules/better-auth/better-auth.middleware.d.ts +1 -0
  39. package/dist/core/modules/better-auth/better-auth.middleware.js +55 -1
  40. package/dist/core/modules/better-auth/better-auth.middleware.js.map +1 -1
  41. package/dist/core/modules/better-auth/better-auth.module.d.ts +1 -1
  42. package/dist/core/modules/better-auth/better-auth.module.js +46 -18
  43. package/dist/core/modules/better-auth/better-auth.module.js.map +1 -1
  44. package/dist/core/modules/better-auth/better-auth.resolver.js +0 -11
  45. package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
  46. package/dist/core/modules/better-auth/better-auth.service.d.ts +22 -1
  47. package/dist/core/modules/better-auth/better-auth.service.js +209 -8
  48. package/dist/core/modules/better-auth/better-auth.service.js.map +1 -1
  49. package/dist/core/modules/better-auth/better-auth.types.d.ts +2 -0
  50. package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
  51. package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +1 -0
  52. package/dist/core/modules/better-auth/core-better-auth.controller.js +15 -2
  53. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
  54. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +7 -0
  55. package/dist/core/modules/better-auth/core-better-auth.resolver.js +72 -12
  56. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
  57. package/dist/core/modules/better-auth/index.d.ts +1 -0
  58. package/dist/core/modules/better-auth/index.js +1 -0
  59. package/dist/core/modules/better-auth/index.js.map +1 -1
  60. package/dist/core/modules/user/core-user.service.d.ts +7 -1
  61. package/dist/core/modules/user/core-user.service.js +57 -3
  62. package/dist/core/modules/user/core-user.service.js.map +1 -1
  63. package/dist/core/modules/user/interfaces/core-user-service-options.interface.d.ts +4 -0
  64. package/dist/core/modules/user/interfaces/core-user-service-options.interface.js +3 -0
  65. package/dist/core/modules/user/interfaces/core-user-service-options.interface.js.map +1 -0
  66. package/dist/core.module.d.ts +3 -0
  67. package/dist/core.module.js +136 -55
  68. package/dist/core.module.js.map +1 -1
  69. package/dist/index.d.ts +5 -0
  70. package/dist/index.js +5 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/server/modules/auth/auth.resolver.js +2 -0
  73. package/dist/server/modules/auth/auth.resolver.js.map +1 -1
  74. package/dist/server/modules/better-auth/better-auth.module.d.ts +1 -1
  75. package/dist/server/modules/better-auth/better-auth.module.js +2 -1
  76. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
  77. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +5 -0
  78. package/dist/server/modules/better-auth/better-auth.resolver.js +27 -11
  79. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -1
  80. package/dist/server/modules/user/user.controller.js +0 -8
  81. package/dist/server/modules/user/user.controller.js.map +1 -1
  82. package/dist/server/modules/user/user.service.d.ts +3 -1
  83. package/dist/server/modules/user/user.service.js +7 -3
  84. package/dist/server/modules/user/user.service.js.map +1 -1
  85. package/dist/tsconfig.build.tsbuildinfo +1 -1
  86. package/package.json +1 -1
  87. package/src/config.env.ts +32 -2
  88. package/src/core/common/interfaces/server-options.interface.ts +304 -58
  89. package/src/core/modules/auth/core-auth.controller.ts +94 -6
  90. package/src/core/modules/auth/core-auth.module.ts +15 -1
  91. package/src/core/modules/auth/core-auth.resolver.ts +71 -3
  92. package/src/core/modules/auth/exceptions/legacy-auth-disabled.exception.ts +35 -0
  93. package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +109 -0
  94. package/src/core/modules/auth/interfaces/auth-provider.interface.ts +86 -0
  95. package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +6 -0
  96. package/src/core/modules/auth/services/core-auth.service.ts +245 -6
  97. package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +283 -0
  98. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +255 -0
  99. package/src/core/modules/better-auth/README.md +565 -208
  100. package/src/core/modules/better-auth/better-auth-migration-status.model.ts +73 -0
  101. package/src/core/modules/better-auth/better-auth-rate-limiter.service.ts +1 -1
  102. package/src/core/modules/better-auth/better-auth-user.mapper.ts +737 -0
  103. package/src/core/modules/better-auth/better-auth.config.ts +45 -15
  104. package/src/core/modules/better-auth/better-auth.middleware.ts +85 -2
  105. package/src/core/modules/better-auth/better-auth.module.ts +83 -27
  106. package/src/core/modules/better-auth/better-auth.resolver.ts +0 -11
  107. package/src/core/modules/better-auth/better-auth.service.ts +367 -12
  108. package/src/core/modules/better-auth/better-auth.types.ts +16 -0
  109. package/src/core/modules/better-auth/core-better-auth.controller.ts +44 -3
  110. package/src/core/modules/better-auth/core-better-auth.resolver.ts +136 -16
  111. package/src/core/modules/better-auth/index.ts +1 -0
  112. package/src/core/modules/user/core-user.service.ts +131 -4
  113. package/src/core/modules/user/interfaces/core-user-service-options.interface.ts +15 -0
  114. package/src/core.module.ts +264 -76
  115. package/src/index.ts +5 -0
  116. package/src/server/modules/auth/auth.resolver.ts +8 -0
  117. package/src/server/modules/better-auth/better-auth.module.ts +9 -3
  118. package/src/server/modules/better-auth/better-auth.resolver.ts +18 -11
  119. package/src/server/modules/user/user.controller.ts +1 -9
  120. package/src/server/modules/user/user.service.ts +4 -2
@@ -2,19 +2,55 @@
2
2
 
3
3
  Integration of the [better-auth](https://better-auth.com) authentication framework with @lenne.tech/nest-server.
4
4
 
5
+ ## TL;DR
6
+
7
+ ```typescript
8
+ // 1. Follow INTEGRATION-CHECKLIST.md to create required files
9
+ // 2. Add to server.module.ts:
10
+ CoreModule.forRoot(envConfig), // IAM-only (new projects)
11
+ BetterAuthModule.forRoot({ config: envConfig.betterAuth, fallbackSecrets: [envConfig.jwt?.secret] }),
12
+
13
+ // 3. Configure in config.env.ts (minimal - JWT enabled by default):
14
+ betterAuth: true // or betterAuth: {} for same effect
15
+
16
+ // With optional features:
17
+ betterAuth: { twoFactor: {}, passkey: {} }
18
+ ```
19
+
20
+ **Quick Links:** [Integration Checklist](./INTEGRATION-CHECKLIST.md) | [REST API](#rest-api-endpoints) | [GraphQL API](#graphql-api) | [Configuration](#configuration)
21
+
22
+ ---
23
+
24
+ ## Table of Contents
25
+
26
+ - [Features](#features)
27
+ - [Quick Integration](#quick-integration-for-claude-code--ai-assistants)
28
+ - [Project Integration Guide](#project-integration-guide-required-steps)
29
+ - [Configuration](#configuration)
30
+ - [REST API Endpoints](#rest-api-endpoints)
31
+ - [GraphQL API](#graphql-api)
32
+ - [CoreModule Signatures](#coremoduleforroot-signatures)
33
+ - [Migration Roadmap](#migration-roadmap-legacy-auth--betterauth)
34
+ - [Password Synchronization](#bidirectional-password-synchronization)
35
+ - [Security Integration](#security-integration)
36
+ - [Troubleshooting](#troubleshooting)
37
+
38
+ ---
39
+
5
40
  ## Features
6
41
 
7
- ### Built-in Plugins (Explicit Configuration)
42
+ ### Built-in Plugins
8
43
 
9
- - **JWT Tokens** - For API clients and stateless authentication
10
- - **Two-Factor Authentication (2FA)** - TOTP-based second factor
11
- - **Passkey/WebAuthn** - Passwordless authentication
44
+ - **JWT Tokens** - For API clients and stateless authentication (**enabled by default**)
45
+ - **Two-Factor Authentication (2FA)** - TOTP-based second factor (opt-in)
46
+ - **Passkey/WebAuthn** - Passwordless authentication (opt-in)
12
47
 
13
48
  ### Core Features
14
49
 
15
50
  - **Email/Password Authentication** - Standard username/password login
16
51
  - **Social Login** - Any OAuth provider (Google, GitHub, Apple, Discord, etc.)
17
52
  - **Parallel Operation** - Runs alongside Legacy Auth without side effects
53
+ - **Bidirectional Sync** - Users can sign in via Legacy Auth or Better-Auth interchangeably
18
54
 
19
55
  ### Extensible via Plugins
20
56
 
@@ -23,75 +59,130 @@ Integration of the [better-auth](https://better-auth.com) authentication framewo
23
59
  - **SSO** - Single Sign-On (OIDC, SAML)
24
60
  - **And many more** - See [Plugins and Extensions](#plugins-and-extensions)
25
61
 
26
- ## Quick Start
62
+ ---
27
63
 
28
- Better-Auth is **enabled by default** and uses sensible defaults. Integration follows the same pattern as Legacy Auth - via an extended module in your project.
64
+ ## Quick Integration (for Claude Code / AI Assistants)
29
65
 
30
- ### 1. Create Extended Module (Recommended)
66
+ **Use [INTEGRATION-CHECKLIST.md](./INTEGRATION-CHECKLIST.md)** for a concise checklist with references to the actual implementation files.
31
67
 
32
- ```typescript
33
- // src/server/modules/better-auth/better-auth.module.ts
34
- import { BetterAuthModule as CoreBetterAuthModule } from '@lenne.tech/nest-server';
68
+ ---
35
69
 
36
- @Module({})
37
- export class BetterAuthModule {
38
- static forRoot(options) {
39
- return {
40
- module: BetterAuthModule,
41
- imports: [CoreBetterAuthModule.forRoot(options)],
42
- };
43
- }
44
- }
70
+ ## Reference Implementation
71
+
72
+ A complete working implementation exists in this package:
73
+
74
+ **Local (in your node_modules):**
75
+ ```
76
+ node_modules/@lenne.tech/nest-server/src/server/modules/better-auth/
45
77
  ```
46
78
 
47
- ### 2. Import in ServerModule
79
+ **GitHub:**
80
+ https://github.com/lenneTech/nest-server/tree/develop/src/server/modules/better-auth
48
81
 
49
- ```typescript
50
- // src/server/server.module.ts
51
- import { BetterAuthModule } from './modules/better-auth/better-auth.module';
82
+ **UserService integration:**
83
+ - Local: `node_modules/@lenne.tech/nest-server/src/server/modules/user/user.service.ts`
84
+ - GitHub: https://github.com/lenneTech/nest-server/blob/develop/src/server/modules/user/user.service.ts
52
85
 
53
- @Module({
54
- imports: [
55
- CoreModule.forRoot(environment),
56
- BetterAuthModule.forRoot({ config: environment.betterAuth }),
57
- ],
58
- })
59
- export class ServerModule {}
86
+ ---
87
+
88
+ ## Project Integration Guide (Required Steps)
89
+
90
+ ### Step 1: Create BetterAuth Module
91
+ **Create:** `src/server/modules/better-auth/better-auth.module.ts`
92
+ **Copy from:** Reference implementation (see above)
93
+
94
+ ### Step 2: Create BetterAuth Resolver (CRITICAL!)
95
+ **Create:** `src/server/modules/better-auth/better-auth.resolver.ts`
96
+ **Copy from:** Reference implementation
97
+
98
+ **WHY must ALL decorators be re-declared?**
99
+ GraphQL schema is built from decorators at compile time. The parent class (`CoreBetterAuthResolver`) is marked as `isAbstract: true`, so its methods are not registered in the schema. You MUST re-declare `@Query`, `@Mutation`, `@Roles` decorators in the child class for the methods to appear in the GraphQL schema.
100
+
101
+ **Note:** `@UseGuards(AuthGuard(JWT))` is NOT needed when using `@Roles(S_USER)` or `@Roles(ADMIN)` because `RolesGuard` already extends `AuthGuard(JWT)` internally.
102
+
103
+ ### Step 3: Create BetterAuth Controller
104
+ **Create:** `src/server/modules/better-auth/better-auth.controller.ts`
105
+ **Copy from:** Reference implementation
106
+
107
+ ### Step 4: Inject BetterAuthUserMapper in UserService (CRITICAL!)
108
+ **Modify:** `src/server/modules/user/user.service.ts`
109
+ **Reference:** See UserService in reference implementation
110
+
111
+ **Required changes:**
112
+
113
+ 1. Add import:
114
+ ```typescript
115
+ import { BetterAuthUserMapper } from '@lenne.tech/nest-server';
116
+ ```
117
+
118
+ 2. Add constructor parameter:
119
+ ```typescript
120
+ @Optional() private readonly betterAuthUserMapper?: BetterAuthUserMapper,
121
+ ```
122
+
123
+ 3. Pass to super() via options object:
124
+ ```typescript
125
+ super(configService, emailService, mainDbModel, mainModelConstructor, { betterAuthUserMapper });
126
+ ```
127
+
128
+ **Why is this critical?**
129
+ The `BetterAuthUserMapper` enables bidirectional password synchronization:
130
+ - User signs up via BetterAuth → password synced to Legacy Auth (bcrypt hash)
131
+ - User changes password → synced between both systems
132
+ - **Without this, users can only authenticate via ONE system!**
133
+
134
+ ### Step 5: Import in ServerModule
135
+ **Modify:** `src/server/server.module.ts`
136
+ **Reference:** See ServerModule in reference implementation
137
+
138
+ Add import and include BetterAuthModule in imports array with `fallbackSecrets`:
139
+
140
+ ```typescript
141
+ BetterAuthModule.forRoot({
142
+ config: envConfig.betterAuth,
143
+ fallbackSecrets: [envConfig.jwt?.secret, envConfig.jwt?.refresh?.secret],
144
+ }),
60
145
  ```
61
146
 
62
- ### 3. Configure (Optional)
147
+ ### Step 6: Configure in config.env.ts
148
+ **Modify:** `src/config.env.ts`
149
+ **Reference:** See config.env.ts in reference implementation
63
150
 
151
+ Add `betterAuth` configuration block. See reference for all available options including `jwt`, `passkey`, `twoFactor`, and `socialProviders`.
152
+
153
+ ---
154
+
155
+ ## Quick Reference
156
+
157
+ **Configuration formats:**
64
158
  ```typescript
65
- // config.env.ts - customize behavior (optional):
66
- const config = {
67
- betterAuth: {
68
- // baseUrl: 'https://your-domain.com',
69
- // basePath: '/iam',
70
- },
71
- };
159
+ betterAuth: true // Enable with all defaults (JWT enabled)
160
+ betterAuth: false // Disable completely
161
+ betterAuth: {} // Same as true
162
+ betterAuth: { ... } // Enable with custom settings
163
+ betterAuth: { enabled: false } // Disable (allows pre-configuration)
72
164
  ```
73
165
 
74
166
  **Default values (used when not configured):**
75
167
 
168
+ - **JWT**: Enabled by default
76
169
  - **Secret**: Falls back to `jwt.secret` → `jwt.refresh.secret` → auto-generated
77
170
  - **Base URL**: `http://localhost:3000`
78
171
  - **Base Path**: `/iam`
79
- - **Passkey Origin**: `http://localhost:3000`
80
- - **Passkey rpId**: `localhost`
81
- - **Passkey rpName**: `Nest Server`
172
+ - **2FA/Passkey**: Disabled (opt-in)
82
173
 
83
174
  To **explicitly disable** Better-Auth:
84
175
 
85
176
  ```typescript
86
177
  const config = {
87
- betterAuth: {
88
- enabled: false,
89
- },
178
+ betterAuth: false, // or betterAuth: { enabled: false }
90
179
  };
91
180
  ```
92
181
 
93
182
  Read the security section below for production deployments.
94
183
 
184
+ ---
185
+
95
186
  ## Understanding Core Settings
96
187
 
97
188
  ### Base URL (`baseUrl`)
@@ -250,28 +341,29 @@ const config = {
250
341
  export default {
251
342
  // ... other config
252
343
 
253
- // OPTIONAL: Better-Auth configuration
254
- // Omit entirely for default behavior, or customize as needed:
344
+ // MINIMAL: Just enable BetterAuth (JWT enabled by default)
345
+ betterAuth: true,
346
+
347
+ // OR with customization:
255
348
  betterAuth: {
256
349
  // enabled: true by default - only set to false to disable
257
350
  // secret: auto-generated if not set (see Security section above)
258
351
  // baseUrl: 'http://localhost:3000', // Default
259
352
  // basePath: '/iam', // Default
260
353
 
261
- // JWT Plugin (enabled by default when config block is present)
262
- // Set enabled: false to explicitly disable
354
+ // JWT Plugin - ENABLED BY DEFAULT (no config needed)
355
+ // Only add this block to customize or explicitly disable
263
356
  jwt: {
264
- expiresIn: '15m',
357
+ expiresIn: '30m', // Default: '15m'
358
+ // enabled: false, // Uncomment to disable JWT
265
359
  },
266
360
 
267
- // Two-Factor Authentication (enabled by default when config block is present)
268
- // Set enabled: false to explicitly disable
361
+ // Two-Factor Authentication (opt-in - requires config block)
269
362
  twoFactor: {
270
363
  appName: 'My Application',
271
364
  },
272
365
 
273
- // Passkey/WebAuthn (enabled by default when config block is present)
274
- // Set enabled: false to explicitly disable
366
+ // Passkey/WebAuthn (opt-in - requires config block)
275
367
  passkey: {
276
368
  rpId: 'localhost',
277
369
  rpName: 'My Application',
@@ -435,23 +527,25 @@ Better-Auth provides a rich plugin ecosystem. This module uses a **hybrid approa
435
527
  - **Built-in plugins** (JWT, 2FA, Passkey): Explicitly configured with typed options
436
528
  - **Additional plugins**: Dynamically added via the `plugins` array
437
529
 
438
- ### Built-in Plugins (Explicit Configuration)
530
+ ### Built-in Plugins
439
531
 
440
- These plugins are enabled by default when their config block is present. **All properties have sensible defaults**, so an empty block `{}` is sufficient!
532
+ | Plugin | Default State | Minimal Config to Enable | Default Values |
533
+ | ------------------ | ------------- | ------------------------ | --------------------------------------------------------------------------------- |
534
+ | **JWT** | **ENABLED** | *(none needed)* | `expiresIn: '15m'` |
535
+ | **Two-Factor** | Disabled | `twoFactor: {}` | `appName: 'Nest Server'` |
536
+ | **Passkey** | Disabled | `passkey: {}` | `origin: 'http://localhost:3000'`, `rpId: 'localhost'`, `rpName: 'Nest Server'` |
441
537
 
442
- | Plugin | Minimal Config | Default Values |
443
- | ------------------ | -------------------- | --------------------------------------------------------------------------------- |
444
- | **JWT** | `jwt: {}` | `expiresIn: '15m'` |
445
- | **Two-Factor** | `twoFactor: {}` | `appName: 'Nest Server'` |
446
- | **Passkey** | `passkey: {}` | `origin: 'http://localhost:3000'`, `rpId: 'localhost'`, `rpName: 'Nest Server'` |
538
+ **JWT is enabled by default** - no configuration needed. 2FA and Passkey require explicit configuration.
447
539
 
448
540
  #### Minimal Syntax (Recommended for Development)
449
541
 
450
542
  ```typescript
451
543
  const config = {
544
+ // JWT is enabled automatically with BetterAuth
545
+ betterAuth: true, // or betterAuth: {}
546
+
547
+ // To also enable 2FA and Passkey:
452
548
  betterAuth: {
453
- // Just add empty blocks - all defaults are applied!
454
- jwt: {},
455
549
  twoFactor: {},
456
550
  passkey: {},
457
551
  },
@@ -474,17 +568,20 @@ const config = {
474
568
  };
475
569
  ```
476
570
 
477
- #### Disabling a Plugin
571
+ #### Disabling Plugins
478
572
 
479
573
  ```typescript
480
574
  const config = {
481
575
  betterAuth: {
482
- jwt: { enabled: false }, // Explicitly disable JWT
483
- twoFactor: {}, // 2FA still enabled with defaults
576
+ jwt: false, // Disable JWT (or jwt: { enabled: false })
577
+ twoFactor: {}, // 2FA enabled with defaults
578
+ passkey: { enabled: false }, // Passkey explicitly disabled
484
579
  },
485
580
  };
486
581
  ```
487
582
 
583
+ **Note:** JWT is the only plugin enabled by default. To disable it, use `jwt: false` or `jwt: { enabled: false }`.
584
+
488
585
  ### Dynamic Plugins (plugins Array)
489
586
 
490
587
  For all other Better-Auth plugins, use the `plugins` array. This provides maximum flexibility without requiring updates to this package.
@@ -615,39 +712,22 @@ const config = {
615
712
 
616
713
  ## Module Setup
617
714
 
618
- Better-Auth is **enabled by default** but requires explicit module integration (`autoRegister: false` by default). This follows the same pattern as Legacy Auth, giving projects full control over customization.
619
-
620
- ### Recommended: Extended Module Pattern
715
+ See the [Project Integration Guide](#project-integration-guide-required-steps) at the top of this document for complete step-by-step instructions.
621
716
 
622
- Projects typically integrate Better-Auth via an extended module:
717
+ ### Summary
623
718
 
624
- ```typescript
625
- // src/server/modules/better-auth/better-auth.module.ts
626
- import { BetterAuthModule as CoreBetterAuthModule } from '@lenne.tech/nest-server';
719
+ Better-Auth is **enabled by default** but requires explicit module integration (`autoRegister: false` by default). This follows the same pattern as Legacy Auth, giving projects full control over customization.
627
720
 
628
- @Module({})
629
- export class BetterAuthModule {
630
- static forRoot(options): DynamicModule {
631
- return {
632
- module: BetterAuthModule,
633
- imports: [CoreBetterAuthModule.forRoot(options)],
634
- };
635
- }
636
- }
721
+ **Required components:**
637
722
 
638
- // src/server/server.module.ts
639
- @Module({
640
- imports: [
641
- CoreModule.forRoot(environment),
642
- BetterAuthModule.forRoot({ config: environment.betterAuth }),
643
- ],
644
- })
645
- export class ServerModule {}
646
- ```
723
+ 1. `BetterAuthModule` - Wraps CoreBetterAuthModule with custom resolver/controller
724
+ 2. `BetterAuthResolver` - Extends CoreBetterAuthResolver for GraphQL operations
725
+ 3. `BetterAuthController` - Extends CoreBetterAuthController for REST endpoints
726
+ 4. `UserService` - Inject `BetterAuthUserMapper` for bidirectional auth sync
647
727
 
648
728
  ### Simple: Auto-Registration
649
729
 
650
- For simple projects without customization needs:
730
+ For simple projects without customization needs (not recommended for production):
651
731
 
652
732
  ```typescript
653
733
  // In config.env.ts
@@ -670,9 +750,9 @@ To explicitly disable Better-Auth:
670
750
 
671
751
  ```typescript
672
752
  const config = {
673
- betterAuth: {
674
- enabled: false,
675
- },
753
+ betterAuth: false, // Simple boolean
754
+ // or
755
+ betterAuth: { enabled: false }, // Allows pre-configuration
676
756
  };
677
757
  ```
678
758
 
@@ -686,10 +766,30 @@ When enabled, Better-Auth exposes the following endpoints at the configured `bas
686
766
  | `/iam/sign-in/email` | POST | Sign in with email/password |
687
767
  | `/iam/sign-out` | GET | Sign out (invalidate session)|
688
768
  | `/iam/session` | GET | Get current session |
769
+ | `/iam/token` | GET | Get fresh JWT token |
689
770
  | `/iam/forgot-password` | POST | Request password reset |
690
771
  | `/iam/reset-password` | POST | Reset password with token |
691
772
  | `/iam/verify-email` | POST | Verify email address |
692
773
 
774
+ ### JWT Token Endpoint
775
+
776
+ The `/iam/token` endpoint returns a fresh JWT token for the current session. Use this when your JWT has expired but your session is still valid.
777
+
778
+ **Request:**
779
+ ```bash
780
+ curl -X GET https://api.example.com/iam/token \
781
+ -H "Cookie: better-auth.session_token=..."
782
+ ```
783
+
784
+ **Response:**
785
+ ```json
786
+ {
787
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6Ii4uLiJ9..."
788
+ }
789
+ ```
790
+
791
+ **Use case:** Microservice authentication - pass the JWT to other services that verify tokens via JWKS (`/iam/jwks`) without database access.
792
+
693
793
  ### Social Login Endpoints
694
794
 
695
795
  | Endpoint | Method | Description |
@@ -718,12 +818,14 @@ In addition to REST endpoints, Better-Auth provides GraphQL queries and mutation
718
818
 
719
819
  ### Queries
720
820
 
721
- | Query | Arguments | Return Type | Description |
722
- | ------------------------ | --------- | ---------------------------- | ------------------------------- |
723
- | `betterAuthEnabled` | - | `Boolean` | Check if Better-Auth is enabled |
724
- | `betterAuthFeatures` | - | `BetterAuthFeaturesModel` | Get enabled features status |
725
- | `betterAuthSession` | - | `BetterAuthSessionModel` | Get current session (auth req.) |
726
- | `betterAuthListPasskeys` | - | `[BetterAuthPasskeyModel]` | List user's passkeys (auth req.)|
821
+ | Query | Arguments | Return Type | Description |
822
+ | ------------------------ | --------- | ---------------------------- | --------------------------------- |
823
+ | `betterAuthEnabled` | - | `Boolean` | Check if Better-Auth is enabled |
824
+ | `betterAuthFeatures` | - | `BetterAuthFeaturesModel` | Get enabled features status |
825
+ | `betterAuthSession` | - | `BetterAuthSessionModel` | Get current session (auth req.) |
826
+ | `betterAuthToken` | - | `String` | Get fresh JWT token (auth req.) |
827
+ | `betterAuthListPasskeys` | - | `[BetterAuthPasskeyModel]` | List user's passkeys (auth req.) |
828
+ | `betterAuthMigrationStatus` | - | `BetterAuthMigrationStatusModel` | Migration status (admin only) |
727
829
 
728
830
  ### Mutations
729
831
 
@@ -1055,9 +1157,132 @@ export class MyService {
1055
1157
  | `hasRole(roles)` | function | Check if user has any of the specified roles |
1056
1158
  | `_authenticatedViaBetterAuth` | true | Marker for Better-Auth authenticated users |
1057
1159
 
1160
+ ## CoreModule.forRoot() Signatures
1161
+
1162
+ Two signatures are available for different use cases:
1163
+
1164
+ ### IAM-Only Signature (Recommended for New Projects)
1165
+
1166
+ ```typescript
1167
+ // server.module.ts
1168
+ @Module({
1169
+ imports: [
1170
+ CoreModule.forRoot(envConfig),
1171
+ BetterAuthModule.forRoot({
1172
+ config: envConfig.betterAuth,
1173
+ fallbackSecrets: [envConfig.jwt?.secret],
1174
+ }),
1175
+ ],
1176
+ })
1177
+ export class ServerModule {}
1178
+ ```
1179
+
1180
+ **Features:**
1181
+ - Simplified setup - no Legacy Auth overhead
1182
+ - GraphQL Subscription authentication via BetterAuth sessions
1183
+ - BetterAuthModule is auto-registered when using this signature
1184
+
1185
+ **Requirements:**
1186
+ - Create BetterAuthModule, Resolver, and Controller in your project
1187
+ - Inject BetterAuthUserMapper in UserService
1188
+ - Set `auth.legacyEndpoints.enabled: false` in config
1189
+
1190
+ ### Legacy + IAM Signature (For Existing Projects)
1191
+
1192
+ ```typescript
1193
+ // server.module.ts
1194
+ @Module({
1195
+ imports: [
1196
+ CoreModule.forRoot(AuthService, AuthModule.forRoot(envConfig.jwt), envConfig),
1197
+ BetterAuthModule.forRoot({
1198
+ config: envConfig.betterAuth,
1199
+ fallbackSecrets: [envConfig.jwt?.secret],
1200
+ }),
1201
+ ],
1202
+ })
1203
+ export class ServerModule {}
1204
+ ```
1205
+
1206
+ > **@deprecated** This 3-parameter signature is deprecated for new projects.
1207
+ > Use the single-parameter signature for new projects.
1208
+
1209
+ **Features:**
1210
+ - Both Legacy Auth and BetterAuth run in parallel
1211
+ - Bidirectional password synchronization
1212
+ - Gradual user migration to IAM
1213
+
1214
+ ---
1215
+
1216
+ ## Migration Roadmap (Legacy Auth → BetterAuth)
1217
+
1218
+ Better-Auth is designed as the successor to Legacy Auth. This section describes the migration path.
1219
+
1220
+ ### Scenario Overview
1221
+
1222
+ | Scenario | Signature | Description |
1223
+ |----------|-----------|-------------|
1224
+ | **1. Legacy Only** | 3-parameter | Existing projects, no IAM integration |
1225
+ | **2. Migration** | 3-parameter | Legacy + IAM parallel operation |
1226
+ | **3. IAM Only** | 1-parameter | New projects, BetterAuth only |
1227
+
1228
+ ### Migration Steps (Scenario 2)
1229
+
1230
+ 1. **Enable BetterAuth**
1231
+ - Follow the [Project Integration Guide](#project-integration-guide-required-steps)
1232
+ - Both systems run in parallel
1233
+
1234
+ 2. **Monitor Migration Progress**
1235
+ ```graphql
1236
+ query {
1237
+ betterAuthMigrationStatus {
1238
+ totalUsers
1239
+ fullyMigratedUsers
1240
+ pendingMigrationUsers
1241
+ migrationPercentage
1242
+ canDisableLegacyAuth
1243
+ }
1244
+ }
1245
+ ```
1246
+ Users migrate automatically when signing in via BetterAuth (IAM).
1247
+
1248
+ 3. **Disable Legacy Endpoints** (when `canDisableLegacyAuth: true`)
1249
+ ```typescript
1250
+ // config.env.ts
1251
+ auth: {
1252
+ legacyEndpoints: {
1253
+ enabled: false // Disables signIn, signUp, logout, refreshToken
1254
+ }
1255
+ }
1256
+ ```
1257
+
1258
+ 4. **Switch to IAM-Only Signature** (optional)
1259
+ ```typescript
1260
+ // Before (deprecated)
1261
+ CoreModule.forRoot(AuthService, AuthModule.forRoot(envConfig.jwt), envConfig)
1262
+
1263
+ // After (recommended)
1264
+ CoreModule.forRoot(envConfig)
1265
+ ```
1266
+
1267
+ ### Why No Automatic Migration Script?
1268
+
1269
+ | System | Password Hash Algorithm |
1270
+ |--------|------------------------|
1271
+ | Legacy Auth | `bcrypt(sha256(password))` |
1272
+ | BetterAuth | `scrypt(sha256(password))` |
1273
+
1274
+ These are **one-way hashes** - there's no way to convert between them without the plain password.
1275
+ Users must sign in at least once via BetterAuth to create a compatible hash.
1276
+
1277
+ ### Detailed Documentation
1278
+
1279
+ See `.claude/rules/module-deprecation.md` for complete migration documentation.
1280
+
1281
+ ---
1282
+
1058
1283
  ## Parallel Operation with Legacy Auth
1059
1284
 
1060
- Better-Auth runs **parallel to Legacy JWT authentication** without conflicts. Both systems are fully compatible because they use the same password hashing (bcrypt) and share the same users collection.
1285
+ Better-Auth runs **parallel to Legacy JWT authentication** without conflicts. Both systems are fully compatible because they share the same users collection.
1061
1286
 
1062
1287
  ### How It Works
1063
1288
 
@@ -1097,6 +1322,224 @@ const legacyToken = await authService.signIn({ email, password });
1097
1322
 
1098
1323
  **No migration is required** - users can authenticate with either system immediately.
1099
1324
 
1325
+ ## Bidirectional Password Synchronization
1326
+
1327
+ ### Overview
1328
+
1329
+ When both Legacy Auth and BetterAuth (IAM) are active, passwords are automatically synchronized between the systems. This ensures users can sign in via either system after any password change or reset.
1330
+
1331
+ ### How Password Sync Works
1332
+
1333
+ | Scenario | Source | Target | Auto-Synced? |
1334
+ |----------|--------|--------|--------------|
1335
+ | Sign up via BetterAuth | IAM | Legacy | ✅ Yes |
1336
+ | Sign up via Legacy Auth | Legacy | IAM | ⚠️ On first IAM sign-in |
1337
+ | Password reset via Legacy | Legacy | IAM | ✅ Yes |
1338
+ | Password reset via BetterAuth | IAM | Legacy | ⚠️ See below |
1339
+ | Password change via user update | Legacy | IAM | ✅ Yes |
1340
+
1341
+ #### IAM Password Reset → Legacy Sync
1342
+
1343
+ When a user resets their password via BetterAuth's native `/iam/reset-password` endpoint, the password is hashed with scrypt before storage. Since we don't have access to the plain password after hashing, we **cannot** automatically sync to Legacy Auth.
1344
+
1345
+ **Solutions:**
1346
+
1347
+ 1. **Recommended: Custom Password Reset Flow**
1348
+ Override the password reset to capture the plain password for sync. See [Custom Password Reset with Sync](#custom-password-reset-with-sync).
1349
+
1350
+ 2. **Use Legacy Password Reset Only**
1351
+ Direct users to the Legacy Auth password reset flow, which syncs to IAM automatically.
1352
+
1353
+ 3. **Re-authenticate After Reset**
1354
+ After IAM password reset, users can sign in via IAM. On next Legacy sign-in attempt, they'll need to reset via Legacy too.
1355
+
1356
+ ### Automatic Sync (No Configuration Required)
1357
+
1358
+ The following sync operations happen automatically when `BetterAuthUserMapper` is injected in `UserService`:
1359
+
1360
+ #### 1. IAM Sign-Up → Legacy
1361
+ When a user signs up via BetterAuth (`/iam/sign-up/email`), the password is hashed with bcrypt and stored in `users.password`, enabling Legacy Auth sign-in.
1362
+
1363
+ #### 2. Legacy Password Reset → IAM
1364
+ When a user resets their password via `CoreUserService.resetPassword()`, the new password is synced to the BetterAuth `account` collection (if the user has a credential account).
1365
+
1366
+ #### 3. Legacy Password Update → IAM
1367
+ When a user changes their password via `UserService.update()`, the new password is synced to BetterAuth (if the user has a credential account).
1368
+
1369
+ #### 4. Legacy → IAM Migration (On First Sign-In)
1370
+ When a legacy user signs in via BetterAuth for the first time, their account is migrated:
1371
+ - Their `iamId` is set
1372
+ - A credential account is created in the `account` collection with the scrypt hash
1373
+
1374
+ ### BetterAuth Password Reset Configuration
1375
+
1376
+ BetterAuth provides native password reset via `/iam/forgot-password` and `/iam/reset-password` endpoints. To enable this, configure the `sendResetPassword` callback:
1377
+
1378
+ ```typescript
1379
+ // config.env.ts
1380
+ betterAuth: {
1381
+ options: {
1382
+ emailAndPassword: {
1383
+ sendResetPassword: async ({ user, url, token }) => {
1384
+ // Send password reset email
1385
+ // 'url' contains the full reset URL with token
1386
+ await emailService.sendEmail({
1387
+ to: user.email,
1388
+ subject: 'Reset Your Password',
1389
+ html: `<a href="${url}">Click here to reset your password</a>`,
1390
+ });
1391
+ },
1392
+ },
1393
+ },
1394
+ },
1395
+ ```
1396
+
1397
+ #### Password Reset Flow (BetterAuth)
1398
+
1399
+ 1. User requests reset: `POST /iam/forgot-password` with `{ email }`
1400
+ 2. BetterAuth generates token and calls `sendResetPassword` callback
1401
+ 3. User clicks link in email → navigates to reset page
1402
+ 4. Frontend submits: `POST /iam/reset-password` with `{ token, newPassword }`
1403
+ 5. BetterAuth updates password in `account` collection
1404
+ 6. Password is automatically synced to Legacy Auth (`users.password`)
1405
+
1406
+ ### Password Hashing Algorithms
1407
+
1408
+ | System | Algorithm | Format |
1409
+ |--------|-----------|--------|
1410
+ | Legacy Auth | bcrypt(sha256(password)) | `$2b$10$...` (60 chars) |
1411
+ | BetterAuth (IAM) | scrypt | `salt:hash` (hex encoded) |
1412
+
1413
+ **Important:** These hashes are NOT interchangeable. Password sync requires re-hashing the plain password with the target algorithm.
1414
+
1415
+ ### Email Change Synchronization
1416
+
1417
+ Email changes are also synchronized bidirectionally:
1418
+
1419
+ | Scenario | Effect |
1420
+ |----------|--------|
1421
+ | Email changed via Legacy (`UserService.update()`) | IAM sessions invalidated (forces re-auth) |
1422
+ | Email changed via IAM | Legacy refresh tokens cleared |
1423
+
1424
+ ### User Deletion Cleanup
1425
+
1426
+ When a user is deleted:
1427
+
1428
+ | Via | Effect |
1429
+ |-----|--------|
1430
+ | Legacy (`UserService.delete()`) | IAM accounts and sessions are cleaned up |
1431
+ | IAM | Legacy user record is removed |
1432
+
1433
+ ### Troubleshooting Password Sync
1434
+
1435
+ #### Password not syncing to IAM
1436
+
1437
+ 1. Verify `BetterAuthUserMapper` is injected in `UserService`:
1438
+ ```typescript
1439
+ constructor(
1440
+ @Optional() private readonly betterAuthUserMapper?: BetterAuthUserMapper,
1441
+ ) {
1442
+ super(..., { betterAuthUserMapper });
1443
+ }
1444
+ ```
1445
+
1446
+ 2. Check if user has an IAM credential account:
1447
+ ```javascript
1448
+ // MongoDB query
1449
+ db.account.findOne({ userId: ObjectId("..."), providerId: "credential" })
1450
+ ```
1451
+
1452
+ 3. Check server logs for sync warnings:
1453
+ ```
1454
+ [CoreUserService] Failed to sync password to IAM...
1455
+ ```
1456
+
1457
+ #### Password reset email not sending
1458
+
1459
+ 1. Configure `sendResetPassword` callback in `betterAuth.options`
1460
+ 2. Check that your email service is working
1461
+ 3. Verify the callback receives `user`, `url`, and `token` parameters
1462
+
1463
+ #### Legacy user can't sign in via IAM
1464
+
1465
+ The user needs to sign in via Legacy Auth first with their password. This triggers the automatic migration on first IAM sign-in attempt.
1466
+
1467
+ Alternatively, use `BetterAuthUserMapper.migrateAccountToIam()` to migrate the user programmatically:
1468
+
1469
+ ```typescript
1470
+ await betterAuthUserMapper.migrateAccountToIam(email, plainPassword);
1471
+ ```
1472
+
1473
+ ### Custom Password Reset with Sync
1474
+
1475
+ To enable bidirectional password reset sync, implement a custom password reset endpoint that captures the plain password and syncs to both systems:
1476
+
1477
+ ```typescript
1478
+ // src/server/modules/better-auth/better-auth.controller.ts
1479
+ import { Body, Controller, Post } from '@nestjs/common';
1480
+ import { CoreBetterAuthController, BetterAuthUserMapper, Roles, RoleEnum } from '@lenne.tech/nest-server';
1481
+
1482
+ @Controller('iam')
1483
+ export class BetterAuthController extends CoreBetterAuthController {
1484
+ constructor(
1485
+ // ... other dependencies
1486
+ private readonly betterAuthUserMapper: BetterAuthUserMapper,
1487
+ ) {
1488
+ super(...);
1489
+ }
1490
+
1491
+ /**
1492
+ * Custom password reset that syncs to both auth systems
1493
+ */
1494
+ @Post('reset-password-sync')
1495
+ @Roles(RoleEnum.S_EVERYONE)
1496
+ async resetPasswordWithSync(
1497
+ @Body() input: { token: string; newPassword: string },
1498
+ ): Promise<{ success: boolean }> {
1499
+ // 1. Reset password via BetterAuth native API
1500
+ const api = this.betterAuthService.getApi();
1501
+ await api.resetPassword({
1502
+ body: { token: input.token, newPassword: input.newPassword },
1503
+ });
1504
+
1505
+ // 2. Sync to Legacy Auth using the plain password
1506
+ // Get user email from the token (you may need to decode it or lookup)
1507
+ const userEmail = await this.getUserEmailFromToken(input.token);
1508
+ if (userEmail) {
1509
+ await this.betterAuthUserMapper.syncPasswordToLegacy(
1510
+ '', // iamUserId not needed for email lookup
1511
+ userEmail,
1512
+ input.newPassword,
1513
+ );
1514
+ }
1515
+
1516
+ return { success: true };
1517
+ }
1518
+
1519
+ private async getUserEmailFromToken(token: string): Promise<string | null> {
1520
+ // Implementation depends on your token structure
1521
+ // You may need to query the database or decode the token
1522
+ return null;
1523
+ }
1524
+ }
1525
+ ```
1526
+
1527
+ **Alternative: Use Legacy Password Reset**
1528
+
1529
+ The simpler approach is to use the Legacy Auth password reset flow, which automatically syncs to IAM:
1530
+
1531
+ ```typescript
1532
+ // Frontend points to Legacy Auth password reset
1533
+ const passwordResetUrl = config.email.passwordResetLink;
1534
+ // e.g., 'http://localhost:4200/user/password-reset'
1535
+
1536
+ // User submits new password via Legacy Auth
1537
+ // → CoreUserService.resetPassword() is called
1538
+ // → Automatically syncs to IAM via syncPasswordChangeToIam()
1539
+ ```
1540
+
1541
+ This is the recommended approach for projects in migration phase where both auth systems are active.
1542
+
1100
1543
  ## Testing
1101
1544
 
1102
1545
  The module provides a `reset()` method for testing:
@@ -1268,121 +1711,35 @@ const config = {
1268
1711
 
1269
1712
  ## Extending Better-Auth (Custom Resolver)
1270
1713
 
1271
- Better-Auth uses the same extension pattern as Legacy Auth. You can extend `CoreBetterAuthResolver` to add custom logic before/after authentication operations.
1714
+ See the [Project Integration Guide](#project-integration-guide-required-steps) for complete setup instructions. This section covers additional customization options.
1272
1715
 
1273
- ### Creating a Custom Resolver
1274
-
1275
- ```typescript
1276
- // src/server/modules/better-auth/better-auth.resolver.ts
1277
- import { Resolver } from '@nestjs/graphql';
1278
- import { Roles } from '@lenne.tech/nest-server';
1279
- import {
1280
- BetterAuthAuthModel,
1281
- BetterAuthService,
1282
- BetterAuthUserMapper,
1283
- CoreBetterAuthResolver,
1284
- RoleEnum,
1285
- } from '@lenne.tech/nest-server';
1286
- import { EmailService } from '../email/email.service';
1287
-
1288
- @Resolver(() => BetterAuthAuthModel)
1289
- @Roles(RoleEnum.ADMIN)
1290
- export class BetterAuthResolver extends CoreBetterAuthResolver {
1291
- constructor(
1292
- betterAuthService: BetterAuthService,
1293
- userMapper: BetterAuthUserMapper,
1294
- private readonly emailService: EmailService,
1295
- ) {
1296
- super(betterAuthService, userMapper);
1297
- }
1716
+ ### Adding Custom Logic
1298
1717
 
1299
- /**
1300
- * Override signUp to send welcome email after registration
1301
- */
1302
- override async betterAuthSignUp(
1303
- email: string,
1304
- password: string,
1305
- name?: string,
1306
- ): Promise<BetterAuthAuthModel> {
1307
- // Call original implementation
1308
- const result = await super.betterAuthSignUp(email, password, name);
1309
-
1310
- // Add custom logic after successful sign-up
1311
- if (result.success && result.user) {
1312
- await this.emailService.sendWelcomeEmail(result.user.email, result.user.name);
1313
- await this.analyticsService.trackSignUp(result.user.id);
1314
- }
1718
+ Override any method to add custom behavior (e.g., sending welcome emails, analytics):
1315
1719
 
1316
- return result;
1720
+ ```typescript
1721
+ // In your BetterAuthResolver (see Step 2 in Integration Guide)
1722
+
1723
+ @Mutation(() => BetterAuthAuthModel, { description: 'Sign up via Better-Auth (email/password)' })
1724
+ @Roles(RoleEnum.S_EVERYONE)
1725
+ override async betterAuthSignUp(
1726
+ @Args('email') email: string,
1727
+ @Args('password') password: string,
1728
+ @Args('name', { nullable: true }) name?: string,
1729
+ ): Promise<BetterAuthAuthModel> {
1730
+ // Call original implementation
1731
+ const result = await super.betterAuthSignUp(email, password, name);
1732
+
1733
+ // Add custom logic after successful sign-up
1734
+ if (result.success && result.user) {
1735
+ await this.emailService.sendWelcomeEmail(result.user.email, result.user.name);
1736
+ await this.analyticsService.trackSignUp(result.user.id);
1317
1737
  }
1318
1738
 
1319
- /**
1320
- * Override signIn to add custom tracking
1321
- */
1322
- override async betterAuthSignIn(
1323
- email: string,
1324
- password: string,
1325
- ctx: { req: Request; res: Response },
1326
- ): Promise<BetterAuthAuthModel> {
1327
- // Add pre-login logic
1328
- this.logger.log(`Login attempt for ${email}`);
1329
-
1330
- const result = await super.betterAuthSignIn(email, password, ctx);
1331
-
1332
- // Add post-login logic
1333
- if (result.success && result.user) {
1334
- await this.analyticsService.trackLogin(result.user.id);
1335
- }
1336
-
1337
- return result;
1338
- }
1739
+ return result;
1339
1740
  }
1340
1741
  ```
1341
1742
 
1342
- ### Registering the Custom Resolver
1343
-
1344
- **Option 1: Via BetterAuthModule options**
1345
-
1346
- ```typescript
1347
- // src/server/server.module.ts
1348
- import { BetterAuthModule } from '@lenne.tech/nest-server';
1349
- import { BetterAuthResolver } from './modules/better-auth/better-auth.resolver';
1350
-
1351
- @Module({
1352
- imports: [
1353
- CoreModule.forRoot(environment),
1354
- BetterAuthModule.forRoot({
1355
- config: environment.betterAuth,
1356
- resolver: BetterAuthResolver, // Your custom resolver
1357
- }),
1358
- ],
1359
- })
1360
- export class ServerModule {}
1361
- ```
1362
-
1363
- **Option 2: Create your own module (like Legacy Auth)**
1364
-
1365
- ```typescript
1366
- // src/server/modules/better-auth/better-auth.module.ts
1367
- import { Module } from '@nestjs/common';
1368
- import { BetterAuthModule as CoreBetterAuthModule } from '@lenne.tech/nest-server';
1369
- import { BetterAuthResolver } from './better-auth.resolver';
1370
- import { EmailModule } from '../email/email.module';
1371
-
1372
- @Module({
1373
- imports: [
1374
- CoreBetterAuthModule.forRoot({
1375
- config: environment.betterAuth,
1376
- resolver: BetterAuthResolver,
1377
- }),
1378
- EmailModule,
1379
- ],
1380
- providers: [BetterAuthResolver],
1381
- exports: [BetterAuthResolver],
1382
- })
1383
- export class BetterAuthModule {}
1384
- ```
1385
-
1386
1743
  ### Available Override Methods
1387
1744
 
1388
1745
  All methods in `CoreBetterAuthResolver` can be overridden: