Skip to content

Commit 9195587

Browse files
ochafikclaude
andcommitted
Fix HTTP Basic authentication in OAuth client
The applyBasicAuth function was incorrectly trying to set headers using array notation on a Headers object. Fixed by using the proper Headers.set() method instead of treating it as a plain object. This ensures that HTTP Basic authentication works correctly when client_secret_basic is the selected authentication method. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 474db45 commit 9195587

File tree

2 files changed

+13
-17
lines changed

2 files changed

+13
-17
lines changed

src/client/auth.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -684,11 +684,11 @@ describe("OAuth Authorization", () => {
684684
expect(body.get("grant_type")).toBe("authorization_code");
685685
expect(body.get("code")).toBe("code123");
686686
expect(body.get("code_verifier")).toBe("verifier123");
687-
expect(body.get("client_id")).toBe("client123");
687+
expect(body.get("client_id")).toBeNull();
688688
expect(body.get("redirect_uri")).toBe("http://localhost:3000/callback");
689689
expect(body.get("example_url")).toBe("https://auth.example.com/token");
690690
expect(body.get("example_param")).toBe("example_value");
691-
expect(body.get("client_secret")).toBeUndefined;
691+
expect(body.get("client_secret")).toBeNull();
692692
});
693693

694694
it("validates token response schema", async () => {
@@ -829,10 +829,10 @@ describe("OAuth Authorization", () => {
829829
const body = mockFetch.mock.calls[0][1].body as URLSearchParams;
830830
expect(body.get("grant_type")).toBe("refresh_token");
831831
expect(body.get("refresh_token")).toBe("refresh123");
832-
expect(body.get("client_id")).toBe("client123");
832+
expect(body.get("client_id")).toBeNull();
833833
expect(body.get("example_url")).toBe("https://auth.example.com/token");
834834
expect(body.get("example_param")).toBe("example_value");
835-
expect(body.get("client_secret")).toBeUndefined;
835+
expect(body.get("client_secret")).toBeNull();
836836
});
837837

838838
it("exchanges refresh token for new tokens and keep existing refresh token if none is returned", async () => {
@@ -1632,7 +1632,7 @@ describe("OAuth Authorization", () => {
16321632
const request = mockFetch.mock.calls[0][1];
16331633

16341634
// Check Authorization header
1635-
const authHeader = request.headers["Authorization"];
1635+
const authHeader = request.headers.get("Authorization");
16361636
const expected = "Basic " + btoa("client123:secret123");
16371637
expect(authHeader).toBe(expected);
16381638

@@ -1660,7 +1660,7 @@ describe("OAuth Authorization", () => {
16601660
const request = mockFetch.mock.calls[0][1];
16611661

16621662
// Check no Authorization header
1663-
expect(request.headers["Authorization"]).toBeUndefined();
1663+
expect(request.headers.get("Authorization")).toBeNull();
16641664

16651665
const body = request.body as URLSearchParams;
16661666
expect(body.get("client_id")).toBe("client123");
@@ -1692,7 +1692,7 @@ describe("OAuth Authorization", () => {
16921692
const request = mockFetch.mock.calls[0][1];
16931693

16941694
// Check no Authorization header
1695-
expect(request.headers["Authorization"]).toBeUndefined();
1695+
expect(request.headers.get("Authorization")).toBeNull();
16961696

16971697
const body = request.body as URLSearchParams;
16981698
expect(body.get("client_id")).toBe("client123");
@@ -1717,7 +1717,7 @@ describe("OAuth Authorization", () => {
17171717
const request = mockFetch.mock.calls[0][1];
17181718

17191719
// Check no Authorization header
1720-
expect(request.headers["Authorization"]).toBeUndefined();
1720+
expect(request.headers.get("Authorization")).toBeNull();
17211721

17221722
const body = request.body as URLSearchParams;
17231723
expect(body.get("client_id")).toBe("client123");
@@ -1770,7 +1770,7 @@ describe("OAuth Authorization", () => {
17701770
const request = mockFetch.mock.calls[0][1];
17711771

17721772
// Check Authorization header
1773-
const authHeader = request.headers["Authorization"];
1773+
const authHeader = request.headers.get("Authorization");
17741774
const expected = "Basic " + btoa("client123:secret123");
17751775
expect(authHeader).toBe(expected);
17761776

@@ -1797,7 +1797,7 @@ describe("OAuth Authorization", () => {
17971797
const request = mockFetch.mock.calls[0][1];
17981798

17991799
// Check no Authorization header
1800-
expect(request.headers["Authorization"]).toBeUndefined();
1800+
expect(request.headers.get("Authorization")).toBeNull();
18011801

18021802
const body = request.body as URLSearchParams;
18031803
expect(body.get("client_id")).toBe("client123");

src/client/auth.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ function selectClientAuthMethod(
167167
function applyClientAuthentication(
168168
method: string,
169169
clientInformation: OAuthClientInformation,
170-
headers: HeadersInit,
170+
headers: Headers,
171171
params: URLSearchParams
172172
): void {
173173
const { client_id, client_secret } = clientInformation;
@@ -193,13 +193,13 @@ function applyClientAuthentication(
193193
/**
194194
* Applies HTTP Basic authentication (RFC 6749 Section 2.3.1)
195195
*/
196-
function applyBasicAuth(clientId: string, clientSecret: string | undefined, headers: HeadersInit): void {
196+
function applyBasicAuth(clientId: string, clientSecret: string | undefined, headers: Headers): void {
197197
if (!clientSecret) {
198198
throw new Error("client_secret_basic authentication requires a client_secret");
199199
}
200200

201201
const credentials = btoa(`${clientId}:${clientSecret}`);
202-
(headers as any)["Authorization"] = `Basic ${credentials}`;
202+
headers.set("Authorization", `Basic ${credentials}`);
203203
}
204204

205205
/**
@@ -635,10 +635,6 @@ export async function exchangeAuthorization(
635635
);
636636
}
637637

638-
// const headers: HeadersInit = {
639-
// "Content-Type": "application/x-www-form-urlencoded",
640-
// };
641-
642638
// // Exchange code for tokens
643639
const headers = new Headers({
644640
"Content-Type": "application/x-www-form-urlencoded",

0 commit comments

Comments
 (0)