@lenne.tech/nest-server 11.7.0 → 11.7.1

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 (89) 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 +17 -0
  4. package/dist/core/modules/auth/core-auth.controller.d.ts +1 -0
  5. package/dist/core/modules/auth/core-auth.controller.js +28 -2
  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 +20 -2
  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-user.mapper.d.ts +33 -0
  32. package/dist/core/modules/better-auth/better-auth-user.mapper.js +443 -0
  33. package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -1
  34. package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +1 -0
  35. package/dist/core/modules/better-auth/core-better-auth.controller.js +15 -2
  36. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
  37. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +2 -0
  38. package/dist/core/modules/better-auth/core-better-auth.resolver.js +14 -0
  39. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
  40. package/dist/core/modules/better-auth/index.d.ts +1 -0
  41. package/dist/core/modules/better-auth/index.js +1 -0
  42. package/dist/core/modules/better-auth/index.js.map +1 -1
  43. package/dist/core/modules/user/core-user.service.d.ts +7 -1
  44. package/dist/core/modules/user/core-user.service.js +57 -3
  45. package/dist/core/modules/user/core-user.service.js.map +1 -1
  46. package/dist/core/modules/user/interfaces/core-user-service-options.interface.d.ts +4 -0
  47. package/dist/core/modules/user/interfaces/core-user-service-options.interface.js +3 -0
  48. package/dist/core/modules/user/interfaces/core-user-service-options.interface.js.map +1 -0
  49. package/dist/core.module.d.ts +3 -0
  50. package/dist/core.module.js +133 -55
  51. package/dist/core.module.js.map +1 -1
  52. package/dist/index.d.ts +5 -0
  53. package/dist/index.js +5 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/server/modules/auth/auth.resolver.js +2 -0
  56. package/dist/server/modules/auth/auth.resolver.js.map +1 -1
  57. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +2 -0
  58. package/dist/server/modules/better-auth/better-auth.resolver.js +13 -0
  59. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -1
  60. package/dist/server/modules/user/user.service.d.ts +3 -1
  61. package/dist/server/modules/user/user.service.js +7 -3
  62. package/dist/server/modules/user/user.service.js.map +1 -1
  63. package/dist/tsconfig.build.tsbuildinfo +1 -1
  64. package/package.json +1 -1
  65. package/src/config.env.ts +32 -2
  66. package/src/core/common/interfaces/server-options.interface.ts +175 -0
  67. package/src/core/modules/auth/core-auth.controller.ts +93 -5
  68. package/src/core/modules/auth/core-auth.module.ts +15 -1
  69. package/src/core/modules/auth/core-auth.resolver.ts +70 -2
  70. package/src/core/modules/auth/exceptions/legacy-auth-disabled.exception.ts +35 -0
  71. package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +109 -0
  72. package/src/core/modules/auth/interfaces/auth-provider.interface.ts +86 -0
  73. package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +6 -0
  74. package/src/core/modules/auth/services/core-auth.service.ts +245 -6
  75. package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +283 -0
  76. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +254 -0
  77. package/src/core/modules/better-auth/README.md +487 -169
  78. package/src/core/modules/better-auth/better-auth-migration-status.model.ts +73 -0
  79. package/src/core/modules/better-auth/better-auth-user.mapper.ts +805 -0
  80. package/src/core/modules/better-auth/core-better-auth.controller.ts +44 -3
  81. package/src/core/modules/better-auth/core-better-auth.resolver.ts +25 -0
  82. package/src/core/modules/better-auth/index.ts +1 -0
  83. package/src/core/modules/user/core-user.service.ts +131 -4
  84. package/src/core/modules/user/interfaces/core-user-service-options.interface.ts +15 -0
  85. package/src/core.module.ts +258 -76
  86. package/src/index.ts +5 -0
  87. package/src/server/modules/auth/auth.resolver.ts +8 -0
  88. package/src/server/modules/better-auth/better-auth.resolver.ts +9 -0
  89. package/src/server/modules/user/user.service.ts +4 -2
@@ -0,0 +1,283 @@
1
+ import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
2
+
3
+ import { IAuthRateLimit } from '../../../common/interfaces/server-options.interface';
4
+ import { ConfigService } from '../../../common/services/config.service';
5
+
6
+ /**
7
+ * Rate limit entry for tracking requests
8
+ */
9
+ interface RateLimitEntry {
10
+ count: number;
11
+ resetTime: number;
12
+ }
13
+
14
+ /**
15
+ * Result of a rate limit check
16
+ *
17
+ * @internal This interface is identical to BetterAuthRateLimiter's RateLimitResult.
18
+ * Use the exported RateLimitResult from better-auth module if needed externally.
19
+ */
20
+ interface RateLimitResult {
21
+ /** Whether the request is allowed */
22
+ allowed: boolean;
23
+ /** Current request count in the window */
24
+ current: number;
25
+ /** Maximum requests allowed */
26
+ limit: number;
27
+ /** Number of remaining requests in the window */
28
+ remaining: number;
29
+ /** Seconds until the rate limit resets */
30
+ resetIn: number;
31
+ }
32
+
33
+ /**
34
+ * Default rate limiting configuration
35
+ */
36
+ const DEFAULT_CONFIG: Required<IAuthRateLimit> = {
37
+ enabled: false,
38
+ max: 10,
39
+ message: 'Too many requests, please try again later.',
40
+ windowSeconds: 60,
41
+ };
42
+
43
+ /**
44
+ * In-memory rate limiter for Legacy Auth endpoints
45
+ *
46
+ * This service provides rate limiting to protect against brute-force attacks
47
+ * on authentication endpoints. It uses an in-memory store with automatic cleanup.
48
+ *
49
+ * Features:
50
+ * - Configurable request limits and time windows
51
+ * - Automatic cleanup of expired entries
52
+ * - IP-based tracking
53
+ * - Auto-configuration from ConfigService
54
+ *
55
+ * Configuration via config.env.ts:
56
+ * ```typescript
57
+ * auth: {
58
+ * rateLimit: {
59
+ * enabled: true,
60
+ * max: 10,
61
+ * windowSeconds: 60,
62
+ * message: 'Too many login attempts, please try again later.',
63
+ * }
64
+ * }
65
+ * ```
66
+ *
67
+ * @since 11.7.x
68
+ */
69
+ @Injectable()
70
+ export class LegacyAuthRateLimiter implements OnModuleInit {
71
+ private readonly logger = new Logger(LegacyAuthRateLimiter.name);
72
+ private readonly store = new Map<string, RateLimitEntry>();
73
+ private config: Required<IAuthRateLimit> = DEFAULT_CONFIG;
74
+ private cleanupInterval: NodeJS.Timeout | null = null;
75
+
76
+ constructor() {
77
+ // Start cleanup interval (every 5 minutes)
78
+ this.startCleanup();
79
+ }
80
+
81
+ /**
82
+ * Auto-configure from ConfigService on module initialization
83
+ */
84
+ onModuleInit(): void {
85
+ const rateLimitConfig = ConfigService.getFastButReadOnly<IAuthRateLimit>('auth.rateLimit');
86
+ if (rateLimitConfig) {
87
+ this.configure(rateLimitConfig);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Configure the rate limiter
93
+ *
94
+ * Follows the "presence implies enabled" pattern:
95
+ * - If config is undefined/null: rate limiting is disabled (backward compatible)
96
+ * - If config is an object (even empty {}): rate limiting is enabled by default
97
+ * - Unless `enabled: false` is explicitly set to disable while pre-configuring
98
+ *
99
+ * @param config - Rate limiting configuration (presence implies enabled)
100
+ */
101
+ configure(config: IAuthRateLimit | null | undefined): void {
102
+ // If config is not provided, rate limiting stays disabled (backward compatible)
103
+ if (config === undefined || config === null) {
104
+ return;
105
+ }
106
+
107
+ // Presence of config implies enabled, unless explicitly disabled
108
+ const enabled = config.enabled !== false;
109
+
110
+ this.config = {
111
+ ...DEFAULT_CONFIG,
112
+ ...config,
113
+ enabled,
114
+ };
115
+
116
+ if (this.config.enabled) {
117
+ this.logger.log(
118
+ `Legacy Auth rate limiting enabled: ${this.config.max} requests per ${this.config.windowSeconds}s`,
119
+ );
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Check if a request is allowed under the rate limit
125
+ *
126
+ * @param ip - Client IP address
127
+ * @param endpoint - Endpoint name (e.g., 'signIn', 'signUp')
128
+ * @returns Rate limit check result
129
+ */
130
+ check(ip: string, endpoint: string): RateLimitResult {
131
+ // If rate limiting is disabled, always allow
132
+ if (!this.config.enabled) {
133
+ return {
134
+ allowed: true,
135
+ current: 0,
136
+ limit: Infinity,
137
+ remaining: Infinity,
138
+ resetIn: 0,
139
+ };
140
+ }
141
+
142
+ const limit = this.config.max;
143
+ const key = `${ip}:${endpoint}`;
144
+ const now = Date.now();
145
+
146
+ // Get or create entry
147
+ let entry = this.store.get(key);
148
+
149
+ if (!entry || now >= entry.resetTime) {
150
+ // Create new entry or reset expired one
151
+ entry = {
152
+ count: 1,
153
+ resetTime: now + this.config.windowSeconds * 1000,
154
+ };
155
+ this.store.set(key, entry);
156
+
157
+ return {
158
+ allowed: true,
159
+ current: 1,
160
+ limit,
161
+ remaining: limit - 1,
162
+ resetIn: this.config.windowSeconds,
163
+ };
164
+ }
165
+
166
+ // Increment count
167
+ entry.count++;
168
+
169
+ const resetIn = Math.ceil((entry.resetTime - now) / 1000);
170
+ const allowed = entry.count <= limit;
171
+ const remaining = Math.max(0, limit - entry.count);
172
+
173
+ if (!allowed) {
174
+ this.logger.warn(`Rate limit exceeded for IP ${this.maskIp(ip)} on ${endpoint}: ${entry.count}/${limit}`);
175
+ }
176
+
177
+ return {
178
+ allowed,
179
+ current: entry.count,
180
+ limit,
181
+ remaining,
182
+ resetIn,
183
+ };
184
+ }
185
+
186
+ /**
187
+ * Get the configured error message
188
+ */
189
+ getMessage(): string {
190
+ return this.config.message;
191
+ }
192
+
193
+ /**
194
+ * Check if rate limiting is enabled
195
+ */
196
+ isEnabled(): boolean {
197
+ return this.config.enabled;
198
+ }
199
+
200
+ /**
201
+ * Reset rate limit for a specific IP (useful for testing or admin override)
202
+ *
203
+ * @param ip - Client IP address
204
+ */
205
+ reset(ip: string): void {
206
+ for (const key of this.store.keys()) {
207
+ if (key.startsWith(`${ip}:`)) {
208
+ this.store.delete(key);
209
+ }
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Clear all rate limit entries (useful for testing)
215
+ */
216
+ clear(): void {
217
+ this.store.clear();
218
+ }
219
+
220
+ /**
221
+ * Get statistics about the rate limiter
222
+ */
223
+ getStats(): { activeEntries: number; enabled: boolean } {
224
+ return {
225
+ activeEntries: this.store.size,
226
+ enabled: this.config.enabled,
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Stop the cleanup interval (for graceful shutdown)
232
+ */
233
+ onModuleDestroy(): void {
234
+ if (this.cleanupInterval) {
235
+ clearInterval(this.cleanupInterval);
236
+ this.cleanupInterval = null;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Mask IP address for logging (privacy)
242
+ */
243
+ private maskIp(ip: string): string {
244
+ if (ip.includes('.')) {
245
+ // IPv4: show first two octets
246
+ const parts = ip.split('.');
247
+ return `${parts[0]}.${parts[1]}.*.*`;
248
+ }
249
+ // IPv6: show first segment
250
+ const parts = ip.split(':');
251
+ return `${parts[0]}:****`;
252
+ }
253
+
254
+ /**
255
+ * Start periodic cleanup of expired entries
256
+ */
257
+ private startCleanup(): void {
258
+ // Clean up every 5 minutes
259
+ this.cleanupInterval = setInterval(
260
+ () => {
261
+ const now = Date.now();
262
+ let cleaned = 0;
263
+
264
+ for (const [key, entry] of this.store.entries()) {
265
+ if (now >= entry.resetTime) {
266
+ this.store.delete(key);
267
+ cleaned++;
268
+ }
269
+ }
270
+
271
+ if (cleaned > 0) {
272
+ this.logger.debug(`Cleaned up ${cleaned} expired rate limit entries`);
273
+ }
274
+ },
275
+ 5 * 60 * 1000,
276
+ );
277
+
278
+ // Prevent the interval from keeping the process alive
279
+ if (this.cleanupInterval.unref) {
280
+ this.cleanupInterval.unref();
281
+ }
282
+ }
283
+ }
@@ -0,0 +1,254 @@
1
+ # BetterAuth Integration Checklist
2
+
3
+ **For integrating BetterAuth into projects using `@lenne.tech/nest-server`.**
4
+
5
+ > **Estimated time:** 10-15 minutes
6
+
7
+ ---
8
+
9
+ ## Choose Your Scenario
10
+
11
+ | Scenario | Use When | CoreModule Signature | Steps |
12
+ |----------|----------|---------------------|-------|
13
+ | **New Project (IAM-Only)** | Starting fresh, no legacy users | `CoreModule.forRoot(envConfig)` | 1-6 |
14
+ | **Existing Project (Migration)** | Have legacy users to migrate | `CoreModule.forRoot(AuthService, AuthModule, envConfig)` | 1-6 |
15
+
16
+ **Key difference:** New projects disable Legacy endpoints, existing projects keep them enabled during migration.
17
+
18
+ ---
19
+
20
+ ## Reference Implementation
21
+
22
+ All files you need to create are already implemented as reference in the package:
23
+
24
+ **Local (in your node_modules):**
25
+ ```
26
+ node_modules/@lenne.tech/nest-server/src/server/modules/better-auth/
27
+ ```
28
+
29
+ **GitHub:**
30
+ https://github.com/lenneTech/nest-server/tree/develop/src/server/modules/better-auth
31
+
32
+ **Also see the UserService integration:**
33
+ - Local: `node_modules/@lenne.tech/nest-server/src/server/modules/user/user.service.ts`
34
+ - GitHub: https://github.com/lenneTech/nest-server/blob/develop/src/server/modules/user/user.service.ts
35
+
36
+ ---
37
+
38
+ ## Required Files (Create in Order)
39
+
40
+ ### 1. BetterAuth Module
41
+ **Create:** `src/server/modules/better-auth/better-auth.module.ts`
42
+ **Copy from:** `node_modules/@lenne.tech/nest-server/src/server/modules/better-auth/better-auth.module.ts`
43
+
44
+ ---
45
+
46
+ ### 2. BetterAuth Controller
47
+ **Create:** `src/server/modules/better-auth/better-auth.controller.ts`
48
+ **Copy from:** `node_modules/@lenne.tech/nest-server/src/server/modules/better-auth/better-auth.controller.ts`
49
+
50
+ ---
51
+
52
+ ### 3. BetterAuth Resolver (CRITICAL!)
53
+ **Create:** `src/server/modules/better-auth/better-auth.resolver.ts`
54
+ **Copy from:** `node_modules/@lenne.tech/nest-server/src/server/modules/better-auth/better-auth.resolver.ts`
55
+
56
+ **WHY must ALL decorators be re-declared?**
57
+ 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`, `@UseGuards` decorators in the child class for the methods to appear in the GraphQL schema.
58
+
59
+ ---
60
+
61
+ ### 4. Update UserService (CRITICAL!)
62
+ **Modify:** `src/server/modules/user/user.service.ts`
63
+ **Reference:** `node_modules/@lenne.tech/nest-server/src/server/modules/user/user.service.ts`
64
+
65
+ **Required changes:**
66
+
67
+ 1. Add import:
68
+ ```typescript
69
+ import { BetterAuthUserMapper } from '@lenne.tech/nest-server';
70
+ ```
71
+
72
+ 2. Add constructor parameter:
73
+ ```typescript
74
+ @Optional() private readonly betterAuthUserMapper?: BetterAuthUserMapper,
75
+ ```
76
+
77
+ 3. Pass to super() via options object:
78
+ ```typescript
79
+ super(configService, emailService, mainDbModel, mainModelConstructor, { betterAuthUserMapper });
80
+ ```
81
+
82
+ **WHY is this critical?**
83
+ The `BetterAuthUserMapper` enables bidirectional password synchronization:
84
+ - User signs up via BetterAuth → password synced to Legacy Auth (bcrypt hash)
85
+ - User changes password → synced between both systems
86
+ - **Without this, users can only authenticate via ONE system!**
87
+
88
+ ---
89
+
90
+ ### 5. Update ServerModule
91
+ **Modify:** `src/server/server.module.ts`
92
+ **Reference:** `node_modules/@lenne.tech/nest-server/src/server/server.module.ts`
93
+
94
+ #### For New Projects (IAM-Only) - Recommended:
95
+ ```typescript
96
+ @Module({
97
+ imports: [
98
+ CoreModule.forRoot(envConfig), // Simplified signature
99
+ BetterAuthModule.forRoot({
100
+ config: envConfig.betterAuth,
101
+ fallbackSecrets: [envConfig.jwt?.secret],
102
+ }),
103
+ // ... other modules
104
+ ],
105
+ })
106
+ export class ServerModule {}
107
+ ```
108
+
109
+ #### For Existing Projects (Migration):
110
+ ```typescript
111
+ @Module({
112
+ imports: [
113
+ CoreModule.forRoot(AuthService, AuthModule.forRoot(envConfig.jwt), envConfig),
114
+ BetterAuthModule.forRoot({
115
+ config: envConfig.betterAuth,
116
+ fallbackSecrets: [envConfig.jwt?.secret],
117
+ }),
118
+ // ... other modules
119
+ ],
120
+ })
121
+ export class ServerModule {}
122
+ ```
123
+
124
+ ---
125
+
126
+ ### 6. Update config.env.ts
127
+ **Modify:** `src/config.env.ts`
128
+ **Reference:** `node_modules/@lenne.tech/nest-server/src/config.env.ts`
129
+
130
+ #### For New Projects (IAM-Only):
131
+ ```typescript
132
+ const config = {
133
+ // Disable Legacy Auth endpoints
134
+ auth: {
135
+ legacyEndpoints: {
136
+ enabled: false,
137
+ },
138
+ },
139
+ // BetterAuth configuration
140
+ betterAuth: {
141
+ // enabled: true (default)
142
+ // basePath: '/iam' (default)
143
+ jwt: {}, // Enable JWT tokens
144
+ twoFactor: {}, // Enable 2FA
145
+ passkey: {}, // Enable Passkeys
146
+ },
147
+ };
148
+ ```
149
+
150
+ #### For Existing Projects (Migration):
151
+ ```typescript
152
+ const config = {
153
+ // Keep Legacy Auth endpoints enabled during migration
154
+ auth: {
155
+ legacyEndpoints: {
156
+ enabled: true, // Default - can disable after migration
157
+ },
158
+ },
159
+ // BetterAuth configuration
160
+ betterAuth: {
161
+ // ... same as above
162
+ },
163
+ };
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Verification Checklist
169
+
170
+ After integration, verify:
171
+
172
+ - [ ] `npm run build` succeeds without errors
173
+ - [ ] `npm test` passes
174
+ - [ ] GraphQL Playground shows `betterAuthEnabled` query
175
+ - [ ] REST endpoint `GET /iam/session` responds
176
+ - [ ] Sign-up via BetterAuth creates user in database with `iamId`
177
+ - [ ] Sign-in via BetterAuth works correctly
178
+
179
+ ### Additional checks for Migration scenario:
180
+ - [ ] Sign-in via Legacy Auth works for BetterAuth-created users
181
+ - [ ] Sign-in via BetterAuth works for Legacy-created users
182
+ - [ ] `betterAuthMigrationStatus` query shows correct counts
183
+
184
+ ---
185
+
186
+ ## Common Mistakes
187
+
188
+ | Mistake | Symptom | Fix |
189
+ |---------|---------|-----|
190
+ | Forgot to re-declare decorators in Resolver | GraphQL endpoints missing (404) | Copy resolver from reference, keep ALL decorators |
191
+ | Forgot `BetterAuthUserMapper` in UserService | Auth systems not synced, users can't cross-authenticate | Add `@Optional()` parameter and pass to super() |
192
+ | Missing `fallbackSecrets` in ServerModule | Session issues without explicit secret | Add `fallbackSecrets: [envConfig.jwt?.secret, ...]` |
193
+ | Wrong `basePath` in config | 404 on BetterAuth endpoints | Ensure basePath matches controller (default: `/iam`) |
194
+ | Using wrong CoreModule signature | Build errors or missing features | New projects: 1-parameter, Existing: 3-parameter |
195
+ | AuthResolver override missing `checkLegacyGraphQLEnabled()` | Legacy endpoint disabling doesn't work (no HTTP 410) | Call `this.checkLegacyGraphQLEnabled('signIn')` in overrides |
196
+
197
+ ---
198
+
199
+ ## Important: AuthResolver Override Pattern
200
+
201
+ If your project has a custom `AuthResolver` that extends `CoreAuthResolver` and overrides `signIn()` or `signUp()`, you **MUST** call the protected check method:
202
+
203
+ ```typescript
204
+ // src/server/modules/auth/auth.resolver.ts
205
+ @Mutation(() => Auth)
206
+ override async signIn(...): Promise<Auth> {
207
+ this.checkLegacyGraphQLEnabled('signIn'); // Required!
208
+ const result = await this.authService.signIn(input, serviceOptions);
209
+ return this.processCookies(ctx, result);
210
+ }
211
+ ```
212
+
213
+ **WHY?** When `auth.legacyEndpoints.enabled: false`, this method throws `LegacyAuthDisabledException` (HTTP 410). Without this call, legacy endpoints remain accessible even when configured as disabled.
214
+
215
+ See: `.claude/rules/module-inheritance.md` for the full pattern.
216
+
217
+ ---
218
+
219
+ ## Client-Side Configuration
220
+
221
+ Clients must be configured to use the correct base path and hash passwords:
222
+
223
+ ```typescript
224
+ // auth-client.ts (e.g., for Nuxt/Vue)
225
+ import { createAuthClient } from 'better-auth/vue';
226
+ import { sha256 } from '~/utils/crypto';
227
+
228
+ const baseClient = createAuthClient({
229
+ baseURL: import.meta.env.VITE_API_URL,
230
+ basePath: '/iam', // Must match server config
231
+ plugins: [...],
232
+ });
233
+
234
+ // Wrap signIn/signUp to hash passwords before sending
235
+ export const authClient = {
236
+ ...baseClient,
237
+ signIn: {
238
+ ...baseClient.signIn,
239
+ email: async (params) => {
240
+ const hashedPassword = await sha256(params.password);
241
+ return baseClient.signIn.email({ ...params, password: hashedPassword });
242
+ },
243
+ },
244
+ // ... same for signUp, resetPassword, etc.
245
+ };
246
+ ```
247
+
248
+ ---
249
+
250
+ ## Detailed Documentation
251
+
252
+ For complete configuration options, API reference, and advanced topics:
253
+ - **README.md:** `node_modules/@lenne.tech/nest-server/src/core/modules/better-auth/README.md`
254
+ - **GitHub:** https://github.com/lenneTech/nest-server/blob/develop/src/core/modules/better-auth/README.md