Skip to content

Commit 0e4de87

Browse files
authored
Merge pull request #28 from script-development/security/stream-request-honors-credentials
security(http): streamRequest honors withCredentials option
2 parents 82f0eba + d8fbed4 commit 0e4de87

4 files changed

Lines changed: 41 additions & 3 deletions

File tree

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/http/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@script-development/fs-http",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"description": "Framework-agnostic HTTP service factory with middleware architecture",
55
"homepage": "https://packages.script.nl/packages/http",
66
"license": "MIT",

packages/http/src/http.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,16 @@ export const createHttpService = (baseURL: string, options?: HttpServiceOptions)
139139

140140
const base = apiUrl.toString().replace(/\/+$/, "");
141141

142+
// Honor the service's withCredentials config. Previously hardcoded to
143+
// "include", which silently overrode consumer opt-outs. Note: smartCredentials
144+
// is a no-op here because streamRequest only accepts relative endpoints
145+
// (base + endpoint is string concatenation), so requests are always same-host.
146+
const includeCredentials: boolean = options?.withCredentials ?? true;
147+
142148
return fetch(base + endpoint, {
143149
signal,
144150
method: "POST",
145-
credentials: "include",
151+
credentials: includeCredentials ? "include" : "same-origin",
146152
headers,
147153
body: JSON.stringify(data),
148154
});

packages/http/tests/http.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,38 @@ describe("createHttpService", () => {
670670
}),
671671
);
672672
});
673+
674+
it("honors withCredentials: false by sending same-origin credentials mode", async () => {
675+
// Arrange
676+
const service = createHttpService(BASE_URL, { withCredentials: false });
677+
const mockFetch = vi.fn(() => Promise.resolve(new Response("ok")));
678+
vi.stubGlobal("fetch", mockFetch);
679+
680+
// Act
681+
await service.streamRequest("/stream", {});
682+
683+
// Assert
684+
expect(mockFetch).toHaveBeenCalledWith(
685+
expect.any(String),
686+
expect.objectContaining({ credentials: "same-origin" }),
687+
);
688+
});
689+
690+
it("honors explicit withCredentials: true by sending include credentials mode", async () => {
691+
// Arrange
692+
const service = createHttpService(BASE_URL, { withCredentials: true });
693+
const mockFetch = vi.fn(() => Promise.resolve(new Response("ok")));
694+
vi.stubGlobal("fetch", mockFetch);
695+
696+
// Act
697+
await service.streamRequest("/stream", {});
698+
699+
// Assert
700+
expect(mockFetch).toHaveBeenCalledWith(
701+
expect.any(String),
702+
expect.objectContaining({ credentials: "include" }),
703+
);
704+
});
673705
});
674706
});
675707

0 commit comments

Comments
 (0)