@lenne.tech/nest-server 11.43.0 → 11.43.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/package-management.md +7 -1
- package/.claude/rules/testing.md +4 -4
- package/FRAMEWORK-API.md +1 -1
- package/dist/core/modules/better-auth/core-better-auth.service.js +9 -0
- package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/migration-guides/11.43.0-to-11.43.1.md +73 -0
- package/migration-guides/11.43.1-to-11.43.2.md +81 -0
- package/package.json +1 -1
- package/src/core/modules/better-auth/core-better-auth.service.ts +21 -3
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Migration Guide: 11.43.0 → 11.43.1
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Bugfixes** | Bearer JWTs issued by Better-Auth are accepted again when only the server's `baseUrl` is set (`NSC__BASE_URL`, every `lt dev up`) — they answered **401** on every request since 11.10.3 (§1) |
|
|
8
|
+
| **New Features** | None |
|
|
9
|
+
| **Framework API** | `CoreBetterAuthService.getBaseUrl()` returns the ORIGIN of the base URL the Better-Auth instance runs on (§1). No changed signatures, no new exports |
|
|
10
|
+
| **Dependencies** | Unchanged |
|
|
11
|
+
| **Breaking Changes** | None |
|
|
12
|
+
| **Migration Effort** | None. A workaround that set `betterAuth.baseUrl` next to `baseUrl` can be removed (§1) |
|
|
13
|
+
|
|
14
|
+
## Quick Migration
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm update @lenne.tech/nest-server
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Vendor-mode projects pick it up with the core update. No code or configuration change is required.
|
|
21
|
+
|
|
22
|
+
## 1. Bearer JWTs answered 401 when only the server `baseUrl` was set
|
|
23
|
+
|
|
24
|
+
Better-Auth signs every JWT with `iss` and `aud` set to the base URL it runs on. `createBetterAuthInstance()`
|
|
25
|
+
resolves that base URL as `betterAuth.baseUrl` → the server's `baseUrl` → the localhost default, and Better-Auth
|
|
26
|
+
stores the **origin** of the result. The framework verified Bearer JWTs against
|
|
27
|
+
`CoreBetterAuthService.getBaseUrl()`, which read only `betterAuth.baseUrl` and otherwise answered
|
|
28
|
+
`http://localhost:3000`.
|
|
29
|
+
|
|
30
|
+
So as soon as a deployment set the server's `baseUrl` without also setting `betterAuth.baseUrl`, the two disagreed,
|
|
31
|
+
and every Bearer JWT was refused with `401 #LTNS_0100` (`unexpected "iss" claim value` in the debug log). That is the
|
|
32
|
+
configuration `nest-server-starter` ships (`baseUrl: process.env.BASE_URL`), every stage that sets `NSC__BASE_URL`,
|
|
33
|
+
and every `lt dev up`. Cookie sessions were unaffected, so the defect surfaced only for clients in JWT mode — for
|
|
34
|
+
example `@lenne.tech/nuxt-extensions` once it switches to JWT after the login, which then received 401 on every
|
|
35
|
+
request.
|
|
36
|
+
|
|
37
|
+
`getBaseUrl()` now reads the base URL off the live Better-Auth instance and returns its origin — exactly the value
|
|
38
|
+
Better-Auth signs with. A trailing slash, a path or a default port in the configured value
|
|
39
|
+
(`https://api.example.com/`, `https://example.com/api`, `https://api.example.com:443`) is not part of the claim and
|
|
40
|
+
no longer causes a mismatch either.
|
|
41
|
+
|
|
42
|
+
**What to check:**
|
|
43
|
+
|
|
44
|
+
- **You set `betterAuth.baseUrl` (or `NSC__BETTER_AUTH__BASE_URL`) only to work around this:** it can go. It still
|
|
45
|
+
wins over the server's `baseUrl` when set, so leaving it in place changes nothing.
|
|
46
|
+
- **Your own code calls `getBaseUrl()`:** it now returns the URL Better-Auth actually runs on, as an origin. Code
|
|
47
|
+
that joined an absolute path onto it (`new URL('/iam/sign-in/email', getBaseUrl())`) keeps working; code that
|
|
48
|
+
relied on a path being part of the returned value must append that path itself. With only the server's `baseUrl`
|
|
49
|
+
set, it now answers that URL instead of `http://localhost:3000`.
|
|
50
|
+
- **A vendor-mode project patched `getBaseUrl()` locally** for the same reason: the patch becomes obsolete with this
|
|
51
|
+
core update and can be dropped.
|
|
52
|
+
|
|
53
|
+
## Compatibility Notes
|
|
54
|
+
|
|
55
|
+
| Pattern | Status |
|
|
56
|
+
| ------- | ------ |
|
|
57
|
+
| Only `baseUrl` / `NSC__BASE_URL` set (starter default, `lt dev up`) | Bearer JWTs accepted again |
|
|
58
|
+
| `betterAuth.baseUrl` set explicitly | Unchanged |
|
|
59
|
+
| Neither set (`local` / `ci` / `e2e` defaults) | Unchanged — both sides use `http://localhost:3000` |
|
|
60
|
+
| Cookie-only clients | Unchanged |
|
|
61
|
+
| A JWT naming another issuer | Still refused |
|
|
62
|
+
|
|
63
|
+
## Troubleshooting
|
|
64
|
+
|
|
65
|
+
**Bearer requests still answer 401 after the update**
|
|
66
|
+
Decode the token (`iss` claim) and compare it with `getBaseUrl()`. They must be identical. If they differ, check
|
|
67
|
+
whether `betterAuth.options.baseURL` overrides the base URL with something that is not an absolute URL — then the
|
|
68
|
+
framework falls back to the configured value.
|
|
69
|
+
|
|
70
|
+
## Module Documentation
|
|
71
|
+
|
|
72
|
+
- [Better-Auth module](../src/core/modules/better-auth/README.md)
|
|
73
|
+
- Implementation: `src/core/modules/better-auth/core-better-auth.service.ts` → `getBaseUrl()`, `verifyJwksToken()`
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Migration Guide: 11.43.1 → 11.43.2
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
| -------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Bugfixes** | A fresh dependency resolve passes `pnpm peers check` again — two upstream releases from 2026-10-18/19 made it report unmet peers for `webpack` and `browserslist` (§1) |
|
|
8
|
+
| **New Features** | None |
|
|
9
|
+
| **Framework API** | Unchanged |
|
|
10
|
+
| **Dependencies** | Runtime dependencies unchanged. Build-time only: the `browserslist` override target is raised to `4.29.4`, and `'@nestjs/cli>webpack': '5.112.0'` is new — both in this repository's `pnpm-workspace.yaml`, which your project does not inherit (§1) |
|
|
11
|
+
| **Internal** | `pnpm run build` in this repository no longer rewrites `FRAMEWORK-API.md` when only the date in its header would change. No effect on consumers |
|
|
12
|
+
| **Breaking Changes** | None |
|
|
13
|
+
| **Migration Effort** | None for most projects. A project whose `pnpm peers check` reports one of the two peers below adds or raises one override entry each (§1) |
|
|
14
|
+
|
|
15
|
+
## Quick Migration
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm update @lenne.tech/nest-server
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Vendor-mode projects pick it up with the core update. No code or configuration change is required.
|
|
22
|
+
|
|
23
|
+
## 1. `pnpm peers check` fails after a fresh resolve
|
|
24
|
+
|
|
25
|
+
Two upstream releases broke the peer check for every project that resolves its dependencies anew — a fresh
|
|
26
|
+
`lt fullstack init`, a `pnpm update`, a `pnpm run update`, or an install without a lockfile. A lockfile resolved
|
|
27
|
+
before 2026-10-18 hides both, so an existing project usually sees them at its next refresh.
|
|
28
|
+
|
|
29
|
+
**`webpack`, required by `schema-utils`.** `schema-utils` 4.8.0 (published 2026-10-18) declares
|
|
30
|
+
`peerDependencies.webpack: ^5.112.0`. It is reached through webpack's own plugins, while `@nestjs/cli` 11.0.24 — the
|
|
31
|
+
newest 11.x — pins webpack to exactly `5.106.2`. The pin cannot satisfy the peer.
|
|
32
|
+
|
|
33
|
+
**`browserslist`, required by `update-browserslist-db`.** A project that carries the starter's
|
|
34
|
+
`'browserslist@<4.28.7': '4.29.3'` override (a security entry, see [security-overrides](../docs/security-overrides.md))
|
|
35
|
+
also has pnpm rewrite `update-browserslist-db`'s peer range to that target. Consumers the key does not reach — in a
|
|
36
|
+
fullstack workspace the app's CSS tooling, for example — resolve the newer `4.29.4` (published 2026-10-19), so the
|
|
37
|
+
rewritten peer is unmet.
|
|
38
|
+
|
|
39
|
+
Both are build-time only: `nest build` uses tsc unless `nest-cli.json` selects the webpack builder, and nothing at
|
|
40
|
+
runtime imports either package.
|
|
41
|
+
|
|
42
|
+
**What to do:** pnpm overrides apply only to the root of an install, so the entries in this repository do not reach
|
|
43
|
+
your project. If `pnpm peers check` (or `pnpm run check`) reports either peer, add the entries to the `overrides:`
|
|
44
|
+
section of your project's `pnpm-workspace.yaml` (the workspace root in a monorepo):
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
overrides:
|
|
48
|
+
# existing entry from the starter: raise the target only
|
|
49
|
+
'browserslist@<4.28.7': '4.29.4'
|
|
50
|
+
# new: lifts only @nestjs/cli's exact webpack pin, nothing else
|
|
51
|
+
'@nestjs/cli>webpack': '5.112.0'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then run `pnpm install` and `pnpm peers check` again. The webpack entry is parent-scoped on purpose: it moves only the
|
|
55
|
+
CLI's stale pin, so no other consumer is held back. It can go once `@nestjs/cli` requests `webpack >=5.112` itself, or
|
|
56
|
+
with `@nestjs/cli` 12, where webpack is a peer.
|
|
57
|
+
|
|
58
|
+
`nest-server-starter` 11.43.2 carries both entries, so a project created after this release has them already.
|
|
59
|
+
|
|
60
|
+
## Compatibility Notes
|
|
61
|
+
|
|
62
|
+
| Pattern | Status |
|
|
63
|
+
| ------- | ------ |
|
|
64
|
+
| Existing lockfile, no refresh | Unchanged — the peer check stays green until the next resolve |
|
|
65
|
+
| Fresh resolve without the entries | `pnpm peers check` reports `webpack` and/or `browserslist` — add the entries (§1) |
|
|
66
|
+
| `nest-cli.json` with the webpack builder (`nest build --webpack`) | Builds with webpack 5.112.0 once the entry is in place |
|
|
67
|
+
| Runtime behaviour | Unchanged — no runtime dependency moved |
|
|
68
|
+
|
|
69
|
+
## Troubleshooting
|
|
70
|
+
|
|
71
|
+
**`pnpm peers check` still reports `webpack` after adding the entry**
|
|
72
|
+
Check that the key is exactly `'@nestjs/cli>webpack'` and that the entry sits in the `pnpm-workspace.yaml` of the
|
|
73
|
+
install root. pnpm 11 reads overrides only from there, not from `package.json`.
|
|
74
|
+
|
|
75
|
+
**pnpm refuses `4.29.4` or `5.112.0` with `ERR_PNPM_NO_MATURE_MATCHING_VERSION`**
|
|
76
|
+
Your project enforces a `minimumReleaseAge` window that these versions have not cleared yet. Wait until they have
|
|
77
|
+
rather than adding an exclusion.
|
|
78
|
+
|
|
79
|
+
## Module Documentation
|
|
80
|
+
|
|
81
|
+
- [Security overrides — why yours are not inherited](../docs/security-overrides.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.43.
|
|
3
|
+
"version": "11.43.2",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -697,9 +697,27 @@ export class CoreBetterAuthService implements OnApplicationBootstrap, OnModuleIn
|
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
/**
|
|
700
|
-
* Gets the base URL
|
|
700
|
+
* Gets the base URL Better-Auth runs on: the ORIGIN of the `baseURL` the live instance was built with.
|
|
701
|
+
*
|
|
702
|
+
* Read off the instance rather than off `betterAuth.baseUrl`, because `createBetterAuthInstance()`
|
|
703
|
+
* resolves it as `betterAuth.baseUrl` → the server's `baseUrl` → localhost default. Better-Auth signs
|
|
704
|
+
* every JWT with the origin of that value as `iss` and `aud` (`createAuthContext()` stores
|
|
705
|
+
* `new URL(baseURL).origin`), so this answers the origin too — a trailing slash, a path or a default
|
|
706
|
+
* port in the configured string is not part of the claim. Until 11.43.1 this read only
|
|
707
|
+
* `betterAuth.baseUrl` and answered `http://localhost:3000` whenever just the server's `baseUrl` was
|
|
708
|
+
* set (`NSC__BASE_URL`, and every `lt dev up`), so the framework refused every Bearer JWT Better-Auth
|
|
709
|
+
* had issued. Without an instance (Better-Auth disabled) it falls back to the configured value.
|
|
701
710
|
*/
|
|
702
711
|
getBaseUrl(): string {
|
|
712
|
+
const instanceBaseUrl = (this.getInstance() as unknown as { options?: { baseURL?: unknown } } | null)?.options
|
|
713
|
+
?.baseURL;
|
|
714
|
+
if (typeof instanceBaseUrl === 'string' && instanceBaseUrl) {
|
|
715
|
+
try {
|
|
716
|
+
return new URL(instanceBaseUrl).origin;
|
|
717
|
+
} catch {
|
|
718
|
+
// Not an absolute URL: Better-Auth cannot derive an origin from it either, so use the configured value.
|
|
719
|
+
}
|
|
720
|
+
}
|
|
703
721
|
return this.config.baseUrl || 'http://localhost:3000';
|
|
704
722
|
}
|
|
705
723
|
|
|
@@ -710,8 +728,8 @@ export class CoreBetterAuthService implements OnApplicationBootstrap, OnModuleIn
|
|
|
710
728
|
* `createBetterAuthInstance()` pins `useSecureCookies: false` (for the cookie NAME) and restores
|
|
711
729
|
* the transport flag through `advanced.defaultCookieAttributes.secure` on an `https://` base URL;
|
|
712
730
|
* 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,
|
|
714
|
-
* {@link getBaseUrl}
|
|
731
|
+
* exactly the answer Better-Auth applies — including the base URL it actually uses, the same source
|
|
732
|
+
* {@link getBaseUrl} reads since 11.43.1.
|
|
715
733
|
*
|
|
716
734
|
* The framework's own cookie helper mirrors this, so a session cookie carries `Secure` no matter
|
|
717
735
|
* which path wrote it.
|