@doswiftly/cli 1.0.2 → 1.1.0
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e6c80ce: Auth route handlers (`createSetTokenHandler`, `createClearTokenHandler`, `createWhoamiHandler`) now accept an optional `isTrustedOrigin` predicate. This unblocks the BFF auth flow when the storefront runs behind a reverse proxy (DoSwiftly hosting, Vercel, custom edge proxy) that rewrites or strips the `Host` header — since 11.3.0 the strict `Origin host = Host` comparison returned 403 for every login, logout, and page-load hydration in that topology, leaving the auth cookie unset and every auth-gated route redirecting to login.
|
|
8
|
+
|
|
9
|
+
### Fix
|
|
10
|
+
|
|
11
|
+
Each handler accepts a new `isTrustedOrigin` callback:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
type OriginValidator = (ctx: {
|
|
15
|
+
origin: string;
|
|
16
|
+
originHost: string;
|
|
17
|
+
request: Request;
|
|
18
|
+
}) => boolean | Promise<boolean>;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
When the predicate returns truthy the strict `Origin host = Host header` comparison is bypassed; when it returns falsy (or is not configured) the existing strict check applies. A thrown predicate fails closed — the error is logged and the strict check applies as if the predicate returned `false`.
|
|
22
|
+
|
|
23
|
+
Two pre-built predicates are exported:
|
|
24
|
+
- `trustedForwardedHostValidator` — passes when `Origin host` equals `X-Forwarded-Host` (falling back to `X-Original-Host`). Use this when a reverse proxy you control sets one of those headers per request. The DoSwiftly hosting platform and Vercel both qualify.
|
|
25
|
+
- `originAllowlistValidator(['https://shop.example.com', 'other-shop.example'])` — passes when `Origin` matches an entry in a static list. Useful when one storefront is hosted on multiple hostnames (custom apex + platform subdomain) and you do not want to depend on forwarded-host headers.
|
|
26
|
+
|
|
27
|
+
### Upgrade impact
|
|
28
|
+
- New storefronts scaffolded via `doswiftly init` ship with `isTrustedOrigin: trustedForwardedHostValidator` configured by default.
|
|
29
|
+
- Existing storefronts using the SDK behind a reverse proxy need a 3-line change to each route handler under `app/api/auth/`:
|
|
30
|
+
```ts
|
|
31
|
+
import {
|
|
32
|
+
createSetTokenHandler,
|
|
33
|
+
trustedForwardedHostValidator,
|
|
34
|
+
} from "@doswiftly/storefront-sdk";
|
|
35
|
+
export const POST = createSetTokenHandler({
|
|
36
|
+
isTrustedOrigin: trustedForwardedHostValidator,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
- Storefronts deployed without a reverse proxy (single-tier hosting where the Next.js process receives traffic directly) need no changes — the default strict check still works because the Host header arrives intact.
|
|
40
|
+
|
|
41
|
+
### Security
|
|
42
|
+
|
|
43
|
+
The predicate is invoked AFTER the Origin header is parsed (rejecting malformed origins) and BEFORE the strict Host comparison. Forwarded-host validation is safe because the trusted intermediary overwrites those headers on every inbound request (`headers.set(...)`, not `append`), so an attacker cannot forge them via a browser `fetch()` — browsers cannot set `X-Forwarded-*` from JavaScript (they are forbidden request headers per the fetch spec).
|
|
44
|
+
|
|
45
|
+
Defense-in-depth layers continue to apply: CORS preflight at the backend, `SameSite=Lax` on the auth cookie, `HttpOnly` + `Secure` cookie attributes, and the strict Origin URL parse (still rejects malformed origin and the `?host=trusted` query-string bypass).
|
|
46
|
+
|
|
3
47
|
## 1.0.2
|
|
4
48
|
|
|
5
49
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import { createClearTokenHandler } from '@doswiftly/storefront-sdk';
|
|
1
|
+
import { createClearTokenHandler, trustedForwardedHostValidator } from '@doswiftly/storefront-sdk';
|
|
2
2
|
|
|
3
|
-
export const POST = createClearTokenHandler(
|
|
3
|
+
export const POST = createClearTokenHandler({
|
|
4
|
+
isTrustedOrigin: trustedForwardedHostValidator,
|
|
5
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import { createSetTokenHandler } from '@doswiftly/storefront-sdk';
|
|
1
|
+
import { createSetTokenHandler, trustedForwardedHostValidator } from '@doswiftly/storefront-sdk';
|
|
2
2
|
|
|
3
|
-
export const POST = createSetTokenHandler(
|
|
3
|
+
export const POST = createSetTokenHandler({
|
|
4
|
+
isTrustedOrigin: trustedForwardedHostValidator,
|
|
5
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { createWhoamiHandler } from '@doswiftly/storefront-sdk';
|
|
1
|
+
import { createWhoamiHandler, trustedForwardedHostValidator } from '@doswiftly/storefront-sdk';
|
|
2
2
|
|
|
3
3
|
export const GET = createWhoamiHandler({
|
|
4
4
|
apiUrl: process.env.NEXT_PUBLIC_API_URL,
|
|
5
5
|
shopSlug: process.env.NEXT_PUBLIC_SHOP_SLUG,
|
|
6
|
+
isTrustedOrigin: trustedForwardedHostValidator,
|
|
6
7
|
});
|