fix(websocket): add API Key query params support and OAuth2 inheritan… (#6271)

* fix(websocket): add API Key query params support and OAuth2 inheritance warning

* add: playwright test
This commit is contained in:
Pooja
2026-01-21 18:56:46 +05:30
committed by GitHub
parent 27b7fa81f2
commit a22eb43a27
6 changed files with 141 additions and 1 deletions

View File

@@ -93,6 +93,17 @@ const WSAuth = ({ item, collection }) => {
case 'inherit': {
const source = getEffectiveAuthSource();
// Check if inherited auth is OAuth2 - not supported for WebSockets
if (source?.auth?.mode === 'oauth2') {
return (
<>
<div className="flex flex-row w-full mt-2 gap-2">
OAuth 2 not <strong>yet</strong> supported by WebSockets. Using no auth instead.
</div>
</>
);
}
// Only show inherited auth if it's one of the supported types
if (source && supportedAuthModes.includes(source.auth?.mode)) {
return (

View File

@@ -249,6 +249,34 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
}
}
// Add API key to the URL if placement is queryparams
if (wsRequest.apiKeyAuthValueForQueryParams && wsRequest.apiKeyAuthValueForQueryParams.placement === 'queryparams') {
try {
const urlObj = new URL(wsRequest.url);
const globalEnvironmentVariables = request.globalEnvironmentVariables;
const promptVariables = collection?.promptVariables || {};
const interpolationOptions = {
globalEnvironmentVariables,
envVars,
runtimeVariables,
promptVariables,
processEnvVars
};
const key = interpolateString(wsRequest.apiKeyAuthValueForQueryParams.key, interpolationOptions);
const value = interpolateString(wsRequest.apiKeyAuthValueForQueryParams.value, interpolationOptions);
urlObj.searchParams.set(key, value);
wsRequest.url = urlObj.toString();
} catch (error) {
console.error('Error adding API key to WebSocket URL:', error);
}
}
delete wsRequest.apiKeyAuthValueForQueryParams;
interpolateVars(wsRequest, envVars, runtimeVariables, processEnvVars);
return wsRequest;
@@ -462,5 +490,6 @@ const registerWsEventHandlers = (window) => {
module.exports = {
registerWsEventHandlers,
wsClient
wsClient,
prepareWsRequest
};

View File

@@ -0,0 +1,55 @@
// Mock dependencies before requiring the module
const { prepareWsRequest } = require('../../src/ipc/network/ws-event-handlers');
describe('prepareWsRequest: API Key Query Params', () => {
const createMockItem = (authConfig = {}) => ({
uid: 'test-item-uid',
request: {
url: 'ws://localhost:3001',
headers: [],
body: {
mode: 'raw',
ws: []
},
auth: authConfig,
vars: { req: [], res: [] },
script: { req: '', res: '' }
}
});
const createMockCollection = (collectionAuth = null) => ({
uid: 'test-collection-uid',
pathname: '/test/path',
root: {
request: {
headers: [],
auth: collectionAuth || { mode: 'none' }
}
},
brunoConfig: {},
globalEnvironmentVariables: {},
promptVariables: {},
items: []
});
describe('API Key with Query Params placement', () => {
it('should append API key to URL when placement is queryparams', async () => {
const item = createMockItem({
mode: 'apikey',
apikey: {
key: 'apiKey',
value: 'test-api-key-123',
placement: 'queryparams'
}
});
const collection = createMockCollection();
const environment = { variables: [] };
const runtimeVariables = {};
const result = await prepareWsRequest(item, collection, environment, runtimeVariables);
expect(result.url).toContain('apiKey=test-api-key-123');
expect(result.url).toBe('ws://localhost:3001/?apiKey=test-api-key-123');
});
});
});

View File

@@ -33,6 +33,12 @@ wss.on('connection', function connection(ws, request) {
return ws.send(JSON.stringify({
headers: request.headers
}));
} else if ('func' in obj && obj.func === 'query') {
const url = new URL(request.url, `http://${request.headers.host}`);
const query = Object.fromEntries(url.searchParams.entries());
return ws.send(JSON.stringify({
query: query
}));
} else {
return ws.send(JSON.stringify({
data: JSON.parse(Buffer.from(data).toString())

View File

@@ -0,0 +1,19 @@
meta {
name: ws-test-request-with-query
type: ws
seq: 3
}
ws {
url: ws://localhost:8081/ws?testParam=testValue&anotherParam={{variable}}
auth: inherit
}
body:ws {
name: message 1
content: '''
{
"func":"query"
}
'''
}

View File

@@ -0,0 +1,20 @@
import { test, expect } from '../../playwright';
import { buildWebsocketCommonLocators } from '../utils/page/locators';
const BRU_REQ_NAME = /^ws-test-request-with-query$/;
test.describe.serial('query params', () => {
test('query params are returned if passed', async ({ pageWithUserData: page }) => {
const locators = buildWebsocketCommonLocators(page);
// Open the most recent collection
await page.locator('#sidebar-collection-name').click();
// Click on the required request
await page.getByTitle(BRU_REQ_NAME).click();
await locators.runner().click();
// Check if the message has the query params
await expect(locators.messages().nth(2).locator('.text-ellipsis')).toHaveText(/\"(testParam)\"\:\s+\"testValue\"/);
});
});