@lenne.tech/nest-server 11.42.10 → 11.42.12

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 (42) hide show
  1. package/.claude/rules/configurable-features.md +1 -1
  2. package/.claude/rules/package-management.md +12 -5
  3. package/.claude/rules/testing.md +10 -8
  4. package/CLAUDE.md +1 -1
  5. package/FRAMEWORK-API.md +1 -1
  6. package/dist/core/common/helpers/cookies.helper.d.ts +3 -2
  7. package/dist/core/common/helpers/cookies.helper.js +13 -4
  8. package/dist/core/common/helpers/cookies.helper.js.map +1 -1
  9. package/dist/core/common/helpers/outbound-url.helper.js +2 -5
  10. package/dist/core/common/helpers/outbound-url.helper.js.map +1 -1
  11. package/dist/core/modules/auth/core-auth.controller.js +2 -1
  12. package/dist/core/modules/auth/core-auth.controller.js.map +1 -1
  13. package/dist/core/modules/auth/core-auth.resolver.js +2 -1
  14. package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
  15. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js +1 -0
  16. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js.map +1 -1
  17. package/dist/core/modules/better-auth/core-better-auth-cookie.helper.d.ts +2 -0
  18. package/dist/core/modules/better-auth/core-better-auth-cookie.helper.js +2 -1
  19. package/dist/core/modules/better-auth/core-better-auth-cookie.helper.js.map +1 -1
  20. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js +7 -2
  21. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js.map +1 -1
  22. package/dist/core/modules/better-auth/core-better-auth.controller.js +1 -0
  23. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
  24. package/dist/core/modules/better-auth/core-better-auth.service.d.ts +1 -0
  25. package/dist/core/modules/better-auth/core-better-auth.service.js +4 -0
  26. package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
  27. package/dist/tsconfig.build.tsbuildinfo +1 -1
  28. package/migration-guides/11.27.2-to-11.27.3.md +4 -2
  29. package/migration-guides/11.36.3-to-11.36.4.md +12 -7
  30. package/migration-guides/11.42.10-to-11.42.11.md +176 -0
  31. package/migration-guides/11.42.11-to-11.42.12.md +142 -0
  32. package/package.json +12 -12
  33. package/src/core/common/helpers/cookies.helper.ts +50 -6
  34. package/src/core/common/helpers/outbound-url.helper.ts +4 -10
  35. package/src/core/modules/auth/core-auth.controller.ts +2 -1
  36. package/src/core/modules/auth/core-auth.resolver.ts +2 -1
  37. package/src/core/modules/better-auth/README.md +1 -0
  38. package/src/core/modules/better-auth/core-better-auth-api.middleware.ts +1 -0
  39. package/src/core/modules/better-auth/core-better-auth-cookie.helper.ts +24 -5
  40. package/src/core/modules/better-auth/core-better-auth-email-verification.service.ts +20 -10
  41. package/src/core/modules/better-auth/core-better-auth.controller.ts +4 -0
  42. package/src/core/modules/better-auth/core-better-auth.service.ts +24 -0
@@ -81,6 +81,16 @@ export interface BetterAuthCookieHelperConfig {
81
81
  * CRITICAL: Required for Passkey/2FA to work correctly.
82
82
  */
83
83
  secret?: string;
84
+ /**
85
+ * Whether Better-Auth's own handlers set `Secure` on the cookies they write
86
+ * (`CoreBetterAuthService.usesSecureCookies()`). `true` makes this helper set it too, whatever the
87
+ * environment, so one session cookie never carries two different transport rules.
88
+ *
89
+ * @since 11.42.12 Before, `secure` followed {@link isProductionLikeEnv} alone, so on the deployed
90
+ * `develop` / `test` stages of a starter-based project the cookie this helper wrote
91
+ * lacked `Secure` while Better-Auth's handlers set it on the same https deployment.
92
+ */
93
+ secureTransport?: boolean;
84
94
  }
85
95
 
86
96
  /**
@@ -146,9 +156,11 @@ export class BetterAuthCookieHelper {
146
156
  /**
147
157
  * Gets the default cookie options for authentication cookies.
148
158
  *
149
- * The `secure` flag is `true` when either `config.env` is production-like
150
- * (`production` / `staging`) or `NODE_ENV === 'production'`. This covers
151
- * staging deployments where only one of the two signals is set.
159
+ * The `secure` flag is `true` when Better-Auth's own cookies are secure (`config.secureTransport`,
160
+ * i.e. an `https://` base URL unless the project opted out), when `config.env` is production-like
161
+ * (`production` / `staging`), or when `NODE_ENV === 'production'`. The first covers every https
162
+ * deployment whatever its environment name; the other two keep `Secure` where real users are
163
+ * certain even if a project switched it off in Better-Auth.
152
164
  *
153
165
  * @returns Cookie options with httpOnly, sameSite, and secure settings
154
166
  */
@@ -156,7 +168,7 @@ export class BetterAuthCookieHelper {
156
168
  const options: AuthCookieOptions = {
157
169
  httpOnly: true,
158
170
  sameSite: 'lax',
159
- secure: isProductionLikeEnv(this.config.env),
171
+ secure: this.config.secureTransport === true || isProductionLikeEnv(this.config.env),
160
172
  };
161
173
 
162
174
  if (this.config.domain) {
@@ -403,7 +415,13 @@ export class BetterAuthCookieHelper {
403
415
  */
404
416
  export function createCookieHelper(
405
417
  basePath: string,
406
- options?: { domain?: string; env?: string; legacyCookieEnabled?: boolean; secret?: string },
418
+ options?: {
419
+ domain?: string;
420
+ env?: string;
421
+ legacyCookieEnabled?: boolean;
422
+ secret?: string;
423
+ secureTransport?: boolean;
424
+ },
407
425
  logger?: Logger,
408
426
  ): BetterAuthCookieHelper {
409
427
  return new BetterAuthCookieHelper({
@@ -413,5 +431,6 @@ export function createCookieHelper(
413
431
  legacyCookieEnabled: options?.legacyCookieEnabled ?? false,
414
432
  logger,
415
433
  secret: options?.secret,
434
+ secureTransport: options?.secureTransport,
416
435
  });
417
436
  }
@@ -4,7 +4,7 @@ import ejs = require('ejs');
4
4
  import * as fs from 'fs';
5
5
  import * as path from 'path';
6
6
 
7
- import { isProductionLikeEnv, resolveAppUrlFromConfig } from '../../common/helpers/cookies.helper';
7
+ import { isLocalEnv, isProductionLikeEnv, resolveAppUrlFromConfig } from '../../common/helpers/cookies.helper';
8
8
  import { maskEmail } from '../../common/helpers/logging.helper';
9
9
  import { IBetterAuthEmailVerificationConfig } from '../../common/interfaces/server-options.interface';
10
10
  import { BrevoService } from '../../common/services/brevo.service';
@@ -838,25 +838,35 @@ export class CoreBetterAuthEmailVerificationService {
838
838
  * Print an auth link (verification / password reset) to stdout for local development.
839
839
  *
840
840
  * The URL embeds a bearer token: the verification link confirms an address, the reset link
841
- * changes a password outright. Neither may reach a deployment holding real accounts, so the gate
842
- * is `isProductionLikeEnv()` — the same two-layer check `EmailService` and the cookie helpers
843
- * already use. `NODE_ENV !== 'production'` alone is NOT enough: a staging deployment sets
844
- * `NODE_ENV=staging` so `getEnvironmentConfig()` loads its config block, which passes that test
845
- * while holding real users.
841
+ * changes a password outright. Neither may reach a deployment's logs, so the link is printed only
842
+ * in a LOCAL environment (`isLocalEnv()`: `local`, `ci`, `e2e`) — an allowlist, not "anything
843
+ * that is not production". Until 11.42.12 the gate was `!isProductionLikeEnv()`, which names only
844
+ * `production` and `staging`; the deployed `develop` and `test` stages of a starter-based project
845
+ * passed it and wrote live reset links into their log pipeline, where log access alone was
846
+ * enough to take over an account.
847
+ *
848
+ * `LT_LOG_AUTH_URLS=1` opts in for another environment that runs on a developer machine (this
849
+ * repository's own `development`, for one); `LT_LOG_AUTH_URLS=0` suppresses it everywhere. A
850
+ * production-like environment never prints, whatever the variable says: the opt-in exists for
851
+ * laptops, and a hard floor keeps it from being the thing that reopens a deployment.
846
852
  *
847
853
  * The address is masked (PII, and the rest of this file already masks it); the URL is printed in
848
- * full because following it without a mail server is the whole point locally. Set
849
- * `LT_LOG_AUTH_URLS=0` to suppress it even outside production.
854
+ * full because following it without a mail server is the whole point locally.
850
855
  *
851
856
  * `console.log` rather than the NestJS logger, deliberately and for two reasons: the logger
852
857
  * buffers, which makes interception unreliable under Vitest, and a logger call would route the
853
858
  * token into `HubLogBufferService`'s ring buffer, which is readable over HTTP by any ADMIN.
854
859
  */
855
860
  protected logAuthUrlForDevelopment(label: string, email: string, url: string): void {
856
- if (process.env.LT_LOG_AUTH_URLS === '0') {
861
+ const optIn = process.env.LT_LOG_AUTH_URLS;
862
+ if (optIn === '0') {
863
+ return;
864
+ }
865
+ const env = this.configService?.getFastButReadOnly<string>('env') ?? process.env.NODE_ENV;
866
+ if (isProductionLikeEnv(env)) {
857
867
  return;
858
868
  }
859
- if (isProductionLikeEnv(this.configService?.getFastButReadOnly<string>('env'))) {
869
+ if (!isLocalEnv(env) && optIn !== '1') {
860
870
  return;
861
871
  }
862
872
  // oxlint-disable-next-line no-console
@@ -268,6 +268,10 @@ export class CoreBetterAuthController {
268
268
  env: this.configService.getFastButReadOnly<string>('env'),
269
269
  legacyCookieEnabled: legacyAuthEnabled,
270
270
  secret: betterAuthConfig?.secret,
271
+ // Mirror Better-Auth's own `Secure` decision, so the cookie this controller writes and the
272
+ // one Better-Auth's handlers write follow the same transport rule on every https deployment.
273
+ // Optional call: a project's test stub of the service may predate the method.
274
+ secureTransport: this.betterAuthService.usesSecureCookies?.() === true,
271
275
  },
272
276
  this.logger,
273
277
  );
@@ -703,6 +703,30 @@ export class CoreBetterAuthService implements OnApplicationBootstrap, OnModuleIn
703
703
  return this.config.baseUrl || 'http://localhost:3000';
704
704
  }
705
705
 
706
+ /**
707
+ * Whether Better-Auth's own handlers set `Secure` on the cookies they write, read off the live
708
+ * instance.
709
+ *
710
+ * `createBetterAuthInstance()` pins `useSecureCookies: false` (for the cookie NAME) and restores
711
+ * the transport flag through `advanced.defaultCookieAttributes.secure` on an `https://` base URL;
712
+ * a project may override either. Reading the instance rather than re-deriving from a URL gives
713
+ * exactly the answer Better-Auth applies — including the base URL it actually uses, which
714
+ * {@link getBaseUrl} does not know when only the server's `baseUrl` is set.
715
+ *
716
+ * The framework's own cookie helper mirrors this, so a session cookie carries `Secure` no matter
717
+ * which path wrote it.
718
+ *
719
+ * @since 11.42.12
720
+ */
721
+ usesSecureCookies(): boolean {
722
+ const advanced = (
723
+ this.getInstance() as unknown as {
724
+ options?: { advanced?: { defaultCookieAttributes?: { secure?: unknown }; useSecureCookies?: unknown } };
725
+ } | null
726
+ )?.options?.advanced;
727
+ return advanced?.useSecureCookies === true || advanced?.defaultCookieAttributes?.secure === true;
728
+ }
729
+
706
730
  /**
707
731
  * Gets the resolved cookie domain for cross-subdomain cookie sharing.
708
732
  *