diff --git a/packages/bruno-requests/src/auth/digestauth-helper.js b/packages/bruno-requests/src/auth/digestauth-helper.js index c1cdc849a..d6b93b98f 100644 --- a/packages/bruno-requests/src/auth/digestauth-helper.js +++ b/packages/bruno-requests/src/auth/digestauth-helper.js @@ -89,9 +89,16 @@ export function addDigestInterceptor(axiosInstance, request) { authDetails.algorithm = 'MD5'; } - const uri = new URL(request.url, request.baseURL || 'http://localhost').pathname; // Handle relative URLs + // Build full URL from the original request (may include query params and baseURL) + const resolvedUrl = new URL( + originalRequest.url || request.url, + originalRequest.baseURL || request.baseURL || 'http://localhost' + ); + const uri = `${resolvedUrl.pathname}${resolvedUrl.search}`; + // Used 'GET' as default method to avoid missing method error + const method = (originalRequest.method || request.method || 'GET').toUpperCase(); const HA1 = md5(`${username}:${authDetails.realm}:${password}`); - const HA2 = md5(`${request.method}:${uri}`); + const HA2 = md5(`${method}:${uri}`); const response = md5( `${HA1}:${authDetails.nonce}:${nonceCount}:${cnonce}:auth:${HA2}` ); diff --git a/packages/bruno-requests/src/auth/digestauth-helper.spec.js b/packages/bruno-requests/src/auth/digestauth-helper.spec.js new file mode 100644 index 000000000..4eb3a405a --- /dev/null +++ b/packages/bruno-requests/src/auth/digestauth-helper.spec.js @@ -0,0 +1,58 @@ +const axios = require('axios'); +const { addDigestInterceptor } = require('./digestauth-helper'); + +describe('Digest Auth with query params', () => { + test('uri should include path and query string', async () => { + const axiosInstance = axios.create(); + + let callCount = 0; + let capturedAuthorization; + + // Custom adapter to simulate a 401 challenge then a 200 success + axiosInstance.defaults.adapter = async (config) => { + callCount += 1; + if (callCount === 1) { + const error = new Error('Unauthorized'); + error.config = config; + error.response = { + status: 401, + headers: { + 'www-authenticate': 'Digest realm="test", nonce="abc", qop="auth"' + } + }; + throw error; + } + + // Second call should have Authorization header set by interceptor + capturedAuthorization = config.headers && (config.headers.Authorization || config.headers.authorization); + return { + status: 200, + statusText: 'OK', + headers: {}, + config, + data: { ok: true } + }; + }; + + const request = { + method: 'GET', + url: 'http://example.com/resource?foo=bar&baz=qux', + headers: {}, + digestConfig: { username: 'user', password: 'pass' } + }; + + addDigestInterceptor(axiosInstance, request); + + const res = await axiosInstance(request); + expect(res.status).toBe(200); + + expect(capturedAuthorization).toBeTruthy(); + // Extract uri="..." from the header + const uriMatch = /uri="([^"]+)"/.exec(capturedAuthorization); + expect(uriMatch).toBeTruthy(); + const uri = uriMatch[1]; + + // Expected to include both pathname and query + expect(uri).toBe('/resource?foo=bar&baz=qux'); + }); +}); \ No newline at end of file