@lenne.tech/nest-server 11.21.3 → 11.22.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.
- package/.claude/rules/architecture.md +79 -0
- package/.claude/rules/better-auth.md +262 -0
- package/.claude/rules/configurable-features.md +308 -0
- package/.claude/rules/core-modules.md +205 -0
- package/.claude/rules/framework-compatibility.md +79 -0
- package/.claude/rules/migration-guides.md +149 -0
- package/.claude/rules/module-deprecation.md +214 -0
- package/.claude/rules/module-inheritance.md +97 -0
- package/.claude/rules/package-management.md +112 -0
- package/.claude/rules/role-system.md +146 -0
- package/.claude/rules/testing.md +120 -0
- package/.claude/rules/versioning.md +53 -0
- package/CLAUDE.md +174 -0
- package/FRAMEWORK-API.md +231 -0
- package/dist/core/common/interfaces/server-options.interface.d.ts +10 -0
- package/dist/core/modules/error-code/error-code.module.js.map +1 -1
- package/dist/core.module.d.ts +3 -3
- package/dist/core.module.js +17 -4
- package/dist/core.module.js.map +1 -1
- package/dist/server/modules/file/file-info.model.d.ts +1 -5
- package/dist/server/modules/user/user.model.d.ts +1 -5
- package/dist/server/server.module.js +6 -6
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +1256 -0
- package/docs/error-codes.md +446 -0
- package/migration-guides/11.10.x-to-11.11.x.md +266 -0
- package/migration-guides/11.11.x-to-11.12.x.md +323 -0
- package/migration-guides/11.12.x-to-11.13.0.md +612 -0
- package/migration-guides/11.13.x-to-11.14.0.md +348 -0
- package/migration-guides/11.14.x-to-11.15.0.md +262 -0
- package/migration-guides/11.15.0-to-11.15.3.md +118 -0
- package/migration-guides/11.15.x-to-11.16.0.md +497 -0
- package/migration-guides/11.16.x-to-11.17.0.md +130 -0
- package/migration-guides/11.17.x-to-11.18.0.md +393 -0
- package/migration-guides/11.18.x-to-11.19.0.md +151 -0
- package/migration-guides/11.19.x-to-11.20.0.md +170 -0
- package/migration-guides/11.20.x-to-11.21.0.md +216 -0
- package/migration-guides/11.21.0-to-11.21.1.md +194 -0
- package/migration-guides/11.21.1-to-11.21.2.md +114 -0
- package/migration-guides/11.21.2-to-11.21.3.md +175 -0
- package/migration-guides/11.21.x-to-11.22.0.md +224 -0
- package/migration-guides/11.22.0-to-11.22.1.md +105 -0
- package/migration-guides/11.3.x-to-11.4.x.md +233 -0
- package/migration-guides/11.6.x-to-11.7.x.md +394 -0
- package/migration-guides/11.7.x-to-11.8.x.md +318 -0
- package/migration-guides/11.8.x-to-11.9.x.md +322 -0
- package/migration-guides/11.9.x-to-11.10.x.md +571 -0
- package/migration-guides/TEMPLATE.md +113 -0
- package/package.json +25 -18
- package/src/core/common/interfaces/server-options.interface.ts +83 -16
- package/src/core/modules/better-auth/CUSTOMIZATION.md +24 -17
- package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +5 -5
- package/src/core/modules/error-code/INTEGRATION-CHECKLIST.md +42 -12
- package/src/core/modules/error-code/error-code.module.ts +4 -9
- package/src/core.module.ts +52 -10
- package/src/server/server.module.ts +7 -9
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# Migration Guide: 11.12.x → 11.13.0
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
|----------|---------|
|
|
7
|
+
| **Breaking Changes** | Email verification enabled by default, `termsAndPrivacyAccepted` required by default on sign-up |
|
|
8
|
+
| **New Features** | Email Verification service, Sign-Up Checks with `termsAndPrivacyAccepted`, `termsAndPrivacyAcceptedAt` user field, TestHelper cookie support |
|
|
9
|
+
| **Bugfixes** | Passkey login response enrichment, Express Response import fix, JWT mode session fallback, Middleware credential fallback (401 fix), RolesGuard REST controller fix |
|
|
10
|
+
| **Security** | `@apollo/server` 5.3.0 → 5.4.0 (DoS vulnerability fix) |
|
|
11
|
+
| **Removed** | `pm2` and `grunt` devDependencies (does not affect consuming projects) |
|
|
12
|
+
| **Migration Effort** | Low (~10 minutes) - Sign-up flow updates + optional email verification configuration |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick Migration
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Update package
|
|
20
|
+
npm install @lenne.tech/nest-server@11.13.0
|
|
21
|
+
|
|
22
|
+
# Verify build
|
|
23
|
+
npm run build
|
|
24
|
+
|
|
25
|
+
# Run tests
|
|
26
|
+
npm test
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Note:** Email verification is now **enabled by default** (zero-config). Sign-up requires `termsAndPrivacyAccepted: true`. See Breaking Changes if you need to restore the previous behavior.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## What's New in 11.13.0
|
|
34
|
+
|
|
35
|
+
### 1. Email Verification (enabled by default)
|
|
36
|
+
|
|
37
|
+
Email verification via Better-Auth's `emailVerification` plugin is now **enabled by default** without any configuration needed:
|
|
38
|
+
|
|
39
|
+
- Users receive a verification email after sign-up
|
|
40
|
+
- `verifiedAt` is automatically set when email is verified
|
|
41
|
+
- Templates provided in German (`de`) and English (`en`)
|
|
42
|
+
- Falls back to nest-server's built-in templates if no project templates exist
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// Zero-config: email verification is active by default
|
|
46
|
+
|
|
47
|
+
// To customize:
|
|
48
|
+
betterAuth: {
|
|
49
|
+
emailVerification: {
|
|
50
|
+
expiresIn: 86400, // Token expiration in seconds (default: 24h)
|
|
51
|
+
template: 'custom-verify', // Custom template name
|
|
52
|
+
locale: 'en', // Template locale (default: 'en')
|
|
53
|
+
brevoTemplateId: 42, // Send via Brevo transactional API (optional)
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// To disable email verification:
|
|
58
|
+
betterAuth: {
|
|
59
|
+
emailVerification: false,
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Configuration behavior:**
|
|
64
|
+
- `undefined` / `null` (no config): **enabled** with defaults
|
|
65
|
+
- `true`: **enabled** with defaults
|
|
66
|
+
- `false`: **disabled**
|
|
67
|
+
- `{}`: **enabled** with defaults
|
|
68
|
+
- `{ locale: 'de' }`: **enabled** with custom settings
|
|
69
|
+
- `{ enabled: false }`: **disabled** (allows pre-configuration)
|
|
70
|
+
|
|
71
|
+
**Brevo Integration:** When `brevoTemplateId` is set and Brevo is configured (`config.brevo`), verification emails are sent via Brevo's transactional API instead of SMTP/EJS templates. Template variables: `name`, `link`, `appName`, `expiresIn`.
|
|
72
|
+
|
|
73
|
+
### 2. Sign-Up Checks (enabled by default)
|
|
74
|
+
|
|
75
|
+
Sign-up validation is now **enabled by default** requiring `termsAndPrivacyAccepted: true`:
|
|
76
|
+
|
|
77
|
+
```graphql
|
|
78
|
+
# Sign-up now requires termsAndPrivacyAccepted
|
|
79
|
+
mutation {
|
|
80
|
+
betterAuthSignUp(
|
|
81
|
+
email: "user@example.com"
|
|
82
|
+
password: "hashedPassword"
|
|
83
|
+
name: "User"
|
|
84
|
+
termsAndPrivacyAccepted: true # Required by default
|
|
85
|
+
) {
|
|
86
|
+
success
|
|
87
|
+
user { id email }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
When accepted, `termsAndPrivacyAcceptedAt` is stored as a `Date` in the user record.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// To disable sign-up checks:
|
|
96
|
+
betterAuth: {
|
|
97
|
+
signUpChecks: false,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// To customize required fields:
|
|
101
|
+
betterAuth: {
|
|
102
|
+
signUpChecks: {
|
|
103
|
+
requiredFields: ['termsAndPrivacyAccepted', 'ageConfirmed'],
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 3. TestHelper Cookie Support
|
|
109
|
+
|
|
110
|
+
The `TestHelper` now supports cookie-based authentication for REST API testing, making it easy to test BetterAuth session-based endpoints:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// Auto-detection: plain session token -> automatically sets iam.session_token + token cookies
|
|
114
|
+
const result = await testHelper.rest('/protected-endpoint', {
|
|
115
|
+
cookies: sessionToken,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Explicit cookie pairs
|
|
119
|
+
const result = await testHelper.rest('/protected-endpoint', {
|
|
120
|
+
cookies: { 'iam.session_token': token, 'custom': 'value' },
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Raw cookie string
|
|
124
|
+
const result = await testHelper.rest('/protected-endpoint', {
|
|
125
|
+
cookies: 'iam.session_token=abc; token=xyz',
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**New static helper methods:**
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Build BetterAuth cookie record from session token
|
|
133
|
+
const cookies = TestHelper.buildBetterAuthCookies(sessionToken);
|
|
134
|
+
|
|
135
|
+
// Extract session token from Set-Cookie response headers
|
|
136
|
+
const token = TestHelper.extractSessionToken(response);
|
|
137
|
+
|
|
138
|
+
// Extract all cookies from response
|
|
139
|
+
const allCookies = TestHelper.extractCookies(response);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`token` (Authorization header) and `cookies` (Cookie header) can be used simultaneously without conflict.
|
|
143
|
+
|
|
144
|
+
Full documentation: `src/test/README.md`
|
|
145
|
+
|
|
146
|
+
### 4. `termsAndPrivacyAcceptedAt` User Field
|
|
147
|
+
|
|
148
|
+
A new `termsAndPrivacyAcceptedAt` field is added to `CoreUserModel`:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Available on user objects
|
|
152
|
+
user.termsAndPrivacyAcceptedAt // Date | undefined
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This field is automatically set when a user signs up with `termsAndPrivacyAccepted: true`.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Breaking Changes
|
|
160
|
+
|
|
161
|
+
### 1. Email Verification Now Enabled by Default
|
|
162
|
+
|
|
163
|
+
**Before (11.12.x):** Email verification was disabled when no `emailVerification` config was present.
|
|
164
|
+
|
|
165
|
+
**After (11.13.0):** Email verification is enabled by default. Users must verify their email after sign-up.
|
|
166
|
+
|
|
167
|
+
**Impact:** New sign-ups will trigger a verification email. Unverified users may be restricted depending on your role configuration (e.g., `S_VERIFIED`).
|
|
168
|
+
|
|
169
|
+
**To restore old behavior:**
|
|
170
|
+
```typescript
|
|
171
|
+
// config.env.ts
|
|
172
|
+
betterAuth: {
|
|
173
|
+
emailVerification: false,
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 2. Sign-Up Now Requires `termsAndPrivacyAccepted`
|
|
178
|
+
|
|
179
|
+
**Impact:** Sign-up via BetterAuth will fail if `termsAndPrivacyAccepted: true` is not provided.
|
|
180
|
+
|
|
181
|
+
**Before (11.12.x):**
|
|
182
|
+
```graphql
|
|
183
|
+
mutation {
|
|
184
|
+
betterAuthSignUp(email: "user@example.com", password: "pass", name: "User") {
|
|
185
|
+
success
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**After (11.13.0):**
|
|
191
|
+
```graphql
|
|
192
|
+
mutation {
|
|
193
|
+
betterAuthSignUp(
|
|
194
|
+
email: "user@example.com"
|
|
195
|
+
password: "pass"
|
|
196
|
+
name: "User"
|
|
197
|
+
termsAndPrivacyAccepted: true # Now required!
|
|
198
|
+
) {
|
|
199
|
+
success
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**To restore old behavior:**
|
|
205
|
+
```typescript
|
|
206
|
+
// config.env.ts
|
|
207
|
+
betterAuth: {
|
|
208
|
+
signUpChecks: false,
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**For custom resolvers:** Update your `BetterAuthResolver` to include the new parameter and inject `CoreBetterAuthSignUpValidatorService`:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { CoreBetterAuthSignUpValidatorService } from '@lenne.tech/nest-server';
|
|
216
|
+
|
|
217
|
+
constructor(
|
|
218
|
+
betterAuthService: CoreBetterAuthService,
|
|
219
|
+
userMapper: CoreBetterAuthUserMapper,
|
|
220
|
+
@Optional() signUpValidator?: CoreBetterAuthSignUpValidatorService,
|
|
221
|
+
) {
|
|
222
|
+
super(betterAuthService, userMapper, signUpValidator);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@Mutation(() => CoreBetterAuthAuthModel)
|
|
226
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
227
|
+
override async betterAuthSignUp(
|
|
228
|
+
@Args('email') email: string,
|
|
229
|
+
@Args('password') password: string,
|
|
230
|
+
@Args('name', { nullable: true }) name?: string,
|
|
231
|
+
@Args('termsAndPrivacyAccepted', { nullable: true }) termsAndPrivacyAccepted?: boolean,
|
|
232
|
+
): Promise<CoreBetterAuthAuthModel> {
|
|
233
|
+
return super.betterAuthSignUp(email, password, name, termsAndPrivacyAccepted);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Detailed Migration Steps
|
|
240
|
+
|
|
241
|
+
### Step 1: Update Package
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npm install @lenne.tech/nest-server@11.13.0
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Step 2: Update Sign-Up Calls
|
|
248
|
+
|
|
249
|
+
If you have sign-up forms or API calls, add `termsAndPrivacyAccepted: true`:
|
|
250
|
+
|
|
251
|
+
**GraphQL:**
|
|
252
|
+
```graphql
|
|
253
|
+
mutation {
|
|
254
|
+
betterAuthSignUp(
|
|
255
|
+
email: "user@example.com"
|
|
256
|
+
password: "hashedPassword"
|
|
257
|
+
name: "User"
|
|
258
|
+
termsAndPrivacyAccepted: true # Add this!
|
|
259
|
+
) {
|
|
260
|
+
success
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**REST API:**
|
|
266
|
+
```json
|
|
267
|
+
POST /iam/sign-up/email
|
|
268
|
+
{
|
|
269
|
+
"email": "user@example.com",
|
|
270
|
+
"password": "hashedPassword",
|
|
271
|
+
"name": "User",
|
|
272
|
+
"termsAndPrivacyAccepted": true
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Or disable the requirement in config.env.ts:**
|
|
277
|
+
```typescript
|
|
278
|
+
betterAuth: {
|
|
279
|
+
signUpChecks: false,
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Step 3: Update Custom Resolvers and Controllers (if applicable)
|
|
284
|
+
|
|
285
|
+
**Custom BetterAuthResolver:** Update to include:
|
|
286
|
+
1. Import `CoreBetterAuthSignUpValidatorService`
|
|
287
|
+
2. Add `@Optional() signUpValidator?` to constructor
|
|
288
|
+
3. Add `termsAndPrivacyAccepted` parameter to `betterAuthSignUp` method
|
|
289
|
+
|
|
290
|
+
See the Breaking Changes section for the code example.
|
|
291
|
+
|
|
292
|
+
**Custom BetterAuthController:** Update to include:
|
|
293
|
+
1. Import `CoreBetterAuthSignUpValidatorService`
|
|
294
|
+
2. Add `@Optional() signUpValidator?` to constructor
|
|
295
|
+
3. Pass it to `super()`:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { CoreBetterAuthSignUpValidatorService } from '@lenne.tech/nest-server';
|
|
299
|
+
|
|
300
|
+
constructor(
|
|
301
|
+
betterAuthService: CoreBetterAuthService,
|
|
302
|
+
userMapper: CoreBetterAuthUserMapper,
|
|
303
|
+
configService: ConfigService,
|
|
304
|
+
@Optional() signUpValidator?: CoreBetterAuthSignUpValidatorService,
|
|
305
|
+
) {
|
|
306
|
+
super(betterAuthService, userMapper, configService, signUpValidator);
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Step 4: Configure Email Verification (optional)
|
|
311
|
+
|
|
312
|
+
If you want to customize email verification behavior:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
// config.env.ts
|
|
316
|
+
betterAuth: {
|
|
317
|
+
emailVerification: {
|
|
318
|
+
locale: 'de', // German email templates
|
|
319
|
+
expiresIn: 172800, // 48h instead of default 24h
|
|
320
|
+
template: 'my-verify', // Custom EJS template name
|
|
321
|
+
},
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Or create custom templates in your project's templates directory:
|
|
326
|
+
- `templates/email-verification-de.ejs` (German)
|
|
327
|
+
- `templates/email-verification-en.ejs` (English)
|
|
328
|
+
- `templates/email-verification.ejs` (Fallback)
|
|
329
|
+
|
|
330
|
+
Available template variables: `name`, `link`, `expiresIn`, `appName`.
|
|
331
|
+
|
|
332
|
+
### Step 5: Test Authentication Flows
|
|
333
|
+
|
|
334
|
+
Test the following flows in your application:
|
|
335
|
+
- [ ] Sign-Up with `termsAndPrivacyAccepted: true` succeeds
|
|
336
|
+
- [ ] Sign-Up without `termsAndPrivacyAccepted` returns error `LTNS_0021`
|
|
337
|
+
- [ ] Email verification link appears in console (local/development mode)
|
|
338
|
+
- [ ] `verifiedAt` is set after email verification
|
|
339
|
+
- [ ] `termsAndPrivacyAcceptedAt` is stored in user record
|
|
340
|
+
- [ ] Email/Password Sign-In works for verified users
|
|
341
|
+
- [ ] Existing users (already verified) are not affected
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Compatibility Notes
|
|
346
|
+
|
|
347
|
+
### Existing Users
|
|
348
|
+
|
|
349
|
+
Existing users in your database are **not affected** by the email verification change. Only new sign-ups trigger verification.
|
|
350
|
+
|
|
351
|
+
### Projects Without BetterAuth
|
|
352
|
+
|
|
353
|
+
If your project does not use BetterAuth (`betterAuth` not configured), these changes have **no impact**.
|
|
354
|
+
|
|
355
|
+
### Frontend Integration
|
|
356
|
+
|
|
357
|
+
Update your sign-up forms to include the `termsAndPrivacyAccepted` checkbox:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// Example: Nuxt/Vue
|
|
361
|
+
const signUp = async () => {
|
|
362
|
+
await authClient.signUp.email({
|
|
363
|
+
email: form.email,
|
|
364
|
+
password: form.password,
|
|
365
|
+
name: form.name,
|
|
366
|
+
termsAndPrivacyAccepted: form.termsAccepted, // Add this
|
|
367
|
+
});
|
|
368
|
+
};
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Troubleshooting
|
|
374
|
+
|
|
375
|
+
### Sign-Up Fails with Error LTNS_0021
|
|
376
|
+
|
|
377
|
+
**Cause:** `termsAndPrivacyAccepted` is not provided or is `false`.
|
|
378
|
+
|
|
379
|
+
**Solution:** Ensure your sign-up form sends `termsAndPrivacyAccepted: true`, or disable the check:
|
|
380
|
+
```typescript
|
|
381
|
+
betterAuth: {
|
|
382
|
+
signUpChecks: false,
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Sign-In Fails with Error LTNS_0023
|
|
387
|
+
|
|
388
|
+
**Cause:** Email verification is enabled (default) and the user has not verified their email yet. The server rejects sign-in attempts with `#LTNS_0023: Email verification required`.
|
|
389
|
+
|
|
390
|
+
**Solution:**
|
|
391
|
+
1. Ensure the user clicks the verification link sent via email (check console in local mode)
|
|
392
|
+
2. Or disable email verification:
|
|
393
|
+
```typescript
|
|
394
|
+
betterAuth: {
|
|
395
|
+
emailVerification: false,
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Note:** This check also applies to 2FA verification (`verifyTotp`) and REST sign-in (`POST /iam/sign-in/email`). Unverified users are blocked from all authentication paths.
|
|
400
|
+
|
|
401
|
+
### Users Cannot Sign In After Sign-Up
|
|
402
|
+
|
|
403
|
+
**Cause:** Email verification is enabled, and the user has not verified their email yet.
|
|
404
|
+
|
|
405
|
+
**Solution:** Check your email configuration (SMTP or Brevo). In local/development mode, the verification URL is printed to the console. Users need to click the verification link before signing in with `S_VERIFIED`-protected endpoints.
|
|
406
|
+
|
|
407
|
+
### Email Verification Emails Not Sent
|
|
408
|
+
|
|
409
|
+
**Cause:** No email service configured (no SMTP and no Brevo).
|
|
410
|
+
|
|
411
|
+
**Solution:** Configure either SMTP or Brevo:
|
|
412
|
+
```typescript
|
|
413
|
+
// SMTP
|
|
414
|
+
email: {
|
|
415
|
+
smtp: { host: 'smtp.example.com', port: 587 },
|
|
416
|
+
defaultSender: { email: 'no-reply@example.com', name: 'My App' },
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Or Brevo
|
|
420
|
+
brevo: {
|
|
421
|
+
apiKey: process.env.BREVO_API_KEY,
|
|
422
|
+
}
|
|
423
|
+
betterAuth: {
|
|
424
|
+
emailVerification: {
|
|
425
|
+
brevoTemplateId: 42,
|
|
426
|
+
},
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Note:** The verification URL is always logged to the console regardless of email configuration.
|
|
431
|
+
|
|
432
|
+
### 401 Errors After Switching from Cookie to JWT Mode
|
|
433
|
+
|
|
434
|
+
**Cause:** Stale httpOnly session cookies (`iam.session_token`) from a previous cookie-based configuration persist in the browser. These cookies are sent automatically with requests and can interfere with Bearer token authentication, as the server receives conflicting authentication sources.
|
|
435
|
+
|
|
436
|
+
**Solution:** httpOnly cookies cannot be cleared via JavaScript. Use server-side sign-out to clear them:
|
|
437
|
+
```typescript
|
|
438
|
+
// Call sign-out endpoint with credentials to clear httpOnly cookies
|
|
439
|
+
await fetch('/api/iam/sign-out', { method: 'POST', credentials: 'include' });
|
|
440
|
+
|
|
441
|
+
// Then sign in fresh with the new configuration
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Prevention:** When switching from `cookies: true` to `cookies: false`, ensure all users are signed out first.
|
|
445
|
+
|
|
446
|
+
### BetterAuth Authentication Fails with `cookies: false`
|
|
447
|
+
|
|
448
|
+
**Cause:** When `cookies: false` is set without `betterAuth.jwt: true`, BetterAuth cannot establish sessions. The server will log a startup warning about this misconfiguration.
|
|
449
|
+
|
|
450
|
+
**Solution:** When using `cookies: false`, always enable the JWT plugin:
|
|
451
|
+
```typescript
|
|
452
|
+
// config.env.ts
|
|
453
|
+
{
|
|
454
|
+
cookies: false,
|
|
455
|
+
betterAuth: {
|
|
456
|
+
jwt: true, // Required when cookies: false
|
|
457
|
+
},
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Note:** Even with `jwt: true`, the BetterAuth programmatic API returns session tokens (not JWTs). The JWT plugin enriches only native HTTP handler responses. Session tokens work for authentication via `Authorization: Bearer <session-token>` header.
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Bugfixes
|
|
466
|
+
|
|
467
|
+
### 1. Passkey Login Response Enrichment
|
|
468
|
+
|
|
469
|
+
Better Auth's `@better-auth/passkey` plugin returns only `{ session }` in the verify-authentication response, despite its OpenAPI spec declaring both `{ session, user }`. This caused the frontend to not receive user data after passkey login, preventing proper auth state setup and dashboard redirect.
|
|
470
|
+
|
|
471
|
+
**Fix:** The API middleware now enriches passkey verify-authentication responses by fetching user data from the database when the response only contains a session. No action needed from consumers.
|
|
472
|
+
|
|
473
|
+
### 2. Express Response Import Fix
|
|
474
|
+
|
|
475
|
+
The API middleware imported `Response` from Express, which shadowed the global Web API `Response` constructor. This caused `new Response(...)` calls to fail silently in certain environments (e.g., Vitest SSR). The Express import is now aliased as `ExpressResponse`.
|
|
476
|
+
|
|
477
|
+
### 3. JWT Mode Session Fallback
|
|
478
|
+
|
|
479
|
+
In JWT mode, the session middleware now resolves database sessions for JWT-authenticated users. This ensures that BetterAuth plugin endpoints (2FA, Passkey) can authenticate via session token, even when the client only sends a JWT.
|
|
480
|
+
|
|
481
|
+
The middleware also supports JWT tokens stored in cookies (`lt-jwt-token`), bridging the gap between cookie-based frontend storage and JWT verification.
|
|
482
|
+
|
|
483
|
+
### 4. Cookie/JWT Startup Validation
|
|
484
|
+
|
|
485
|
+
The server now validates authentication configuration at startup and logs warnings for common misconfigurations:
|
|
486
|
+
- `cookies: false` without `betterAuth.jwt: true`
|
|
487
|
+
- Missing BetterAuth secret
|
|
488
|
+
|
|
489
|
+
### 5. Cryptographically Secure ID Generation
|
|
490
|
+
|
|
491
|
+
The `generateId()` method in `CoreBetterAuthUserMapper` now uses `crypto.randomBytes(21)` instead of `Math.random()`. This ensures cryptographically secure random IDs for user mapping and internal token generation.
|
|
492
|
+
|
|
493
|
+
### 6. Middleware Credential Fallback (401 Fix)
|
|
494
|
+
|
|
495
|
+
When a request included an **invalid Authorization header** alongside a **valid session cookie**, the middleware would return 401 instead of falling back to the cookie. This affected three areas:
|
|
496
|
+
|
|
497
|
+
- **`extractSessionToken()` in `core-better-auth-web.helper.ts`**: `isSessionToken()` returned `true` for non-JWT garbage in the Authorization header, preventing cookie fallback. Fix: Added `skipAuthHeader` option, used by Strategy 3 (cookie fallback) when the Auth header was already tried and failed.
|
|
498
|
+
- **`CoreBetterAuthModule.configure()`**: After `reset()` in tests, the `betterAuthEnabled` static field was `false` because the `createDeferredModule()` factory did not re-set it. This caused middleware to not be registered. Fix: `configure()` now only checks `this.betterAuthService?.isEnabled()` (injected instance) instead of the static field.
|
|
499
|
+
- **`createDeferredModule()` factory**: Now also sets `this.betterAuthEnabled = !!this.authInstance` for consistency with `forRootAsync()`.
|
|
500
|
+
|
|
501
|
+
No action needed from consumers — this is a purely internal fix.
|
|
502
|
+
|
|
503
|
+
### 7. RolesGuard REST Controller Fix
|
|
504
|
+
|
|
505
|
+
`RolesGuard.getRequest()` failed for REST controllers because `GqlExecutionContext.create(context).getContext()` returns a truthy value (the `next` function) for HTTP contexts, but `.req` on it is `undefined`.
|
|
506
|
+
|
|
507
|
+
**Before:** `ctx.getContext() ? ctx.getContext().req : context.switchToHttp().getRequest()`
|
|
508
|
+
**After:** `ctx.getContext()?.req || context.switchToHttp().getRequest()`
|
|
509
|
+
|
|
510
|
+
No action needed from consumers — REST controllers with `@Roles()` now work correctly.
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Security Fix
|
|
515
|
+
|
|
516
|
+
### `@apollo/server` Updated to 5.4.0
|
|
517
|
+
|
|
518
|
+
Updated from 5.3.0 to 5.4.0 to fix a **high severity DoS vulnerability**. No API changes — drop-in update.
|
|
519
|
+
|
|
520
|
+
**Action:** Run `npm install` after updating `@lenne.tech/nest-server`.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Removed Dependencies
|
|
525
|
+
|
|
526
|
+
### `pm2` and `grunt` Removed
|
|
527
|
+
|
|
528
|
+
The following devDependencies have been removed from nest-server:
|
|
529
|
+
|
|
530
|
+
| Package | Version | Reason |
|
|
531
|
+
|---------|---------|--------|
|
|
532
|
+
| `pm2` | 6.0.14 | No longer used, had low-severity ReDoS vulnerability |
|
|
533
|
+
| `grunt` | 1.6.1 | Only used for pm2-based production start |
|
|
534
|
+
| `grunt-bg-shell` | 2.3.3 | Grunt plugin |
|
|
535
|
+
| `grunt-contrib-clean` | 2.0.1 | Grunt plugin |
|
|
536
|
+
| `grunt-contrib-watch` | 1.1.0 | Grunt plugin |
|
|
537
|
+
| `grunt-sync` | 0.8.2 | Grunt plugin |
|
|
538
|
+
|
|
539
|
+
The `start:prod` script now uses `NODE_ENV=production node dist/main.js` instead of Grunt.
|
|
540
|
+
|
|
541
|
+
**Impact on consuming projects:** None — these were devDependencies of nest-server and not exposed to consumers. If your project uses pm2 independently, it is not affected.
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## New Exports
|
|
546
|
+
|
|
547
|
+
The following are newly exported from `@lenne.tech/nest-server`:
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
// Email Verification Service
|
|
551
|
+
export { CoreBetterAuthEmailVerificationService } from './core/modules/better-auth/core-better-auth-email-verification.service';
|
|
552
|
+
|
|
553
|
+
// Sign-Up Validator Service
|
|
554
|
+
export { CoreBetterAuthSignUpValidatorService } from './core/modules/better-auth/core-better-auth-signup-validator.service';
|
|
555
|
+
|
|
556
|
+
// Configuration Interfaces
|
|
557
|
+
export { IBetterAuthEmailVerificationConfig, IBetterAuthSignUpChecksConfig } from './core/common/interfaces/server-options.interface';
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## New Test Files
|
|
563
|
+
|
|
564
|
+
| Test File | Coverage |
|
|
565
|
+
|-----------|----------|
|
|
566
|
+
| `tests/stories/better-auth-email-verification.story.test.ts` | Email verification flow, LTNS_0023 enforcement, sign-up with verification |
|
|
567
|
+
| `tests/stories/better-auth-jwt-middleware.story.test.ts` | JWT-to-session resolution, Authorization header priority over cookies, cookie-less mode session handling |
|
|
568
|
+
| `tests/stories/better-auth-security.e2e-spec.ts` | Cookie/JWT startup validation, security configuration checks |
|
|
569
|
+
| `tests/stories/middleware-credential-fallback.e2e-spec.ts` | Middleware credential fallback: all 3 strategies (Auth header, lt-jwt-token cookie, session cookie), invalid header + valid cookie, parallel auth mode |
|
|
570
|
+
|
|
571
|
+
## TestHelper Documentation
|
|
572
|
+
|
|
573
|
+
Full reference for REST, GraphQL, and cookie-based testing:
|
|
574
|
+
- **Documentation:** [src/test/README.md](../src/test/README.md)
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Module Documentation
|
|
579
|
+
|
|
580
|
+
### Better-Auth Module
|
|
581
|
+
|
|
582
|
+
- **README:** [src/core/modules/better-auth/README.md](../src/core/modules/better-auth/README.md)
|
|
583
|
+
- **Integration Checklist:** [src/core/modules/better-auth/INTEGRATION-CHECKLIST.md](../src/core/modules/better-auth/INTEGRATION-CHECKLIST.md)
|
|
584
|
+
- **Customization Guide:** [src/core/modules/better-auth/CUSTOMIZATION.md](../src/core/modules/better-auth/CUSTOMIZATION.md)
|
|
585
|
+
- **Reference Implementation:** `src/server/modules/iam/`
|
|
586
|
+
- **Key Files:**
|
|
587
|
+
- `core-better-auth-email-verification.service.ts` - Email verification logic and template resolution
|
|
588
|
+
- `core-better-auth-signup-validator.service.ts` - Sign-up validation with configurable required fields
|
|
589
|
+
|
|
590
|
+
### Module Registration Patterns
|
|
591
|
+
|
|
592
|
+
When customizing BetterAuth, use the appropriate registration pattern:
|
|
593
|
+
|
|
594
|
+
| Pattern | Use When | Configuration |
|
|
595
|
+
|---------|----------|---------------|
|
|
596
|
+
| **Zero-Config** | No customization | `CoreModule.forRoot(envConfig)` |
|
|
597
|
+
| **Config-based** | Custom Controller/Resolver | `betterAuth: { controller, resolver }` |
|
|
598
|
+
| **Separate Module** | Full control, additional providers | `betterAuth: { autoRegister: false }` |
|
|
599
|
+
|
|
600
|
+
**See [CUSTOMIZATION.md](../src/core/modules/better-auth/CUSTOMIZATION.md) for detailed guidance on:**
|
|
601
|
+
- Customizing Controller, Resolver, and Services
|
|
602
|
+
- Email template customization (EJS and Brevo)
|
|
603
|
+
- Avoiding the "forRoot() called twice" warning
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## References
|
|
608
|
+
|
|
609
|
+
- [Better-Auth Module](../src/core/modules/better-auth/) - Core module implementation
|
|
610
|
+
- [nest-server-starter](https://github.com/lenneTech/nest-server-starter) - Reference implementation
|
|
611
|
+
- [Better-Auth Documentation](https://www.better-auth.com/) - Official Better-Auth docs
|
|
612
|
+
- [Configurable Features Pattern](../.claude/rules/configurable-features.md) - Configuration patterns used
|