diff --git a/packages/api/src/utils/client/httpClient.ts b/packages/api/src/utils/client/httpClient.ts index a97056ac99a3..2c8e282636cd 100644 --- a/packages/api/src/utils/client/httpClient.ts +++ b/packages/api/src/utils/client/httpClient.ts @@ -276,7 +276,7 @@ export class HttpClient implements IHttpClient { const timer = this.metrics?.requestTime.startTimer({routeId}); try { - const url = urlJoin(baseUrl, opts.url) + (opts.query ? "?" + stringifyQuery(opts.query) : ""); + const url = new URL(urlJoin(baseUrl, opts.url) + (opts.query ? "?" + stringifyQuery(opts.query) : "")); const headers = extraHeaders && opts.headers ? {...extraHeaders, ...opts.headers} : opts.headers || extraHeaders || {}; @@ -286,6 +286,12 @@ export class HttpClient implements IHttpClient { if (bearerToken && headers["Authorization"] === undefined) { headers["Authorization"] = `Bearer ${bearerToken}`; } + if ((url.username || url.password) && headers["Authorization"] === undefined) { + headers["Authorization"] = `Basic ${toBase64(`${url.username}:${url.password}`)}`; + // Remove the username and password from the URL + url.username = ""; + url.password = ""; + } this.logger?.debug("HttpClient request", {routeId}); @@ -298,7 +304,7 @@ export class HttpClient implements IHttpClient { if (!res.ok) { const errBody = await res.text(); - throw new HttpError(`${res.statusText}: ${getErrorMessage(errBody)}`, res.status, url); + throw new HttpError(`${res.statusText}: ${getErrorMessage(errBody)}`, res.status, url.toString()); } const streamTimer = this.metrics?.streamTime.startTimer({routeId}); diff --git a/packages/api/test/unit/client/httpClient.test.ts b/packages/api/test/unit/client/httpClient.test.ts index e3cfb6062f3d..be6006d9e375 100644 --- a/packages/api/test/unit/client/httpClient.test.ts +++ b/packages/api/test/unit/client/httpClient.test.ts @@ -135,6 +135,22 @@ describe("httpClient json client", () => { } }); + it("should set user credentials in URL as Authorization header", async () => { + const {baseUrl} = await getServer({ + ...testRoute, + handler: async (req) => { + expect(req.headers.authorization).to.equal("Basic dXNlcjpwYXNzd29yZA=="); + return {}; + }, + }); + const url = new URL(baseUrl); + url.username = "user"; + url.password = "password"; + const httpClient = new HttpClient({baseUrl: url.toString()}); + + await httpClient.json(testRoute); + }); + it("should handle aborting request with timeout", async () => { const {baseUrl} = await getServer({ ...testRoute,