diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index 1445a097921..1a5cd246633 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -235,7 +235,7 @@ const configureRequest = async (
const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token;
if (tokenPlacement == 'header' && tokenValue) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim();
- } else if (tokenValue) {
+ } else if (tokenPlacement == 'url' && tokenValue) {
try {
const url = new URL(request.url);
url.searchParams.set(tokenQueryKey, tokenValue);
@@ -252,7 +252,7 @@ const configureRequest = async (
const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token;
if (tokenPlacement == 'header' && tokenValue) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim();
- } else if (tokenValue) {
+ } else if (tokenPlacement == 'url' && tokenValue) {
try {
const url = new URL(request.url);
url.searchParams.set(tokenQueryKey, tokenValue);
@@ -269,7 +269,7 @@ const configureRequest = async (
const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token;
if (tokenPlacement == 'header' && tokenValue) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim();
- } else if (tokenValue) {
+ } else if (tokenPlacement == 'url' && tokenValue) {
try {
const url = new URL(request.url);
url.searchParams.set(tokenQueryKey, tokenValue);
@@ -286,7 +286,7 @@ const configureRequest = async (
const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token;
if (tokenPlacement == 'header' && tokenValue) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim();
- } else if (tokenValue) {
+ } else if (tokenPlacement == 'url' && tokenValue) {
try {
const url = new URL(request.url);
url.searchParams.set(tokenQueryKey, tokenValue);
diff --git a/packages/bruno-electron/src/ipc/network/prepare-grpc-request.js b/packages/bruno-electron/src/ipc/network/prepare-grpc-request.js
index e8e68b64707..521d1847929 100644
--- a/packages/bruno-electron/src/ipc/network/prepare-grpc-request.js
+++ b/packages/bruno-electron/src/ipc/network/prepare-grpc-request.js
@@ -18,7 +18,7 @@ const processHeaders = (headers) => {
const placeOAuth2Token = (grpcRequest, credentials, tokenPlacement, tokenHeaderPrefix, tokenQueryKey) => {
if (tokenPlacement === 'header') {
grpcRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
- } else {
+ } else if (tokenPlacement === 'url') {
try {
const url = new URL(grpcRequest.url);
url?.searchParams?.set(tokenQueryKey, credentials?.access_token);
diff --git a/packages/bruno-electron/src/ipc/network/ws-event-handlers.js b/packages/bruno-electron/src/ipc/network/ws-event-handlers.js
index b9319838377..b5acad7859c 100644
--- a/packages/bruno-electron/src/ipc/network/ws-event-handlers.js
+++ b/packages/bruno-electron/src/ipc/network/ws-event-handlers.js
@@ -176,7 +176,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
};
if (tokenPlacement == 'header') {
wsRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
- } else {
+ } else if (tokenPlacement == 'url') {
try {
const url = new URL(request.url);
url?.searchParams?.set(tokenQueryKey, credentials?.access_token);
@@ -207,7 +207,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
};
if (tokenPlacement == 'header') {
wsRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
- } else {
+ } else if (tokenPlacement == 'url') {
try {
const url = new URL(request.url);
url?.searchParams?.set(tokenQueryKey, credentials?.access_token);
@@ -238,7 +238,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
};
if (tokenPlacement == 'header') {
wsRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
- } else {
+ } else if (tokenPlacement == 'url') {
try {
const url = new URL(request.url);
url?.searchParams?.set(tokenQueryKey, credentials?.access_token);
diff --git a/packages/bruno-electron/tests/network/index.spec.js b/packages/bruno-electron/tests/network/index.spec.js
index 5fa443132f3..dc43ff57bfe 100644
--- a/packages/bruno-electron/tests/network/index.spec.js
+++ b/packages/bruno-electron/tests/network/index.spec.js
@@ -1,4 +1,19 @@
+jest.mock('../../src/utils/oauth2', () => ({
+ getOAuth2TokenUsingAuthorizationCode: jest.fn(),
+ getOAuth2TokenUsingClientCredentials: jest.fn(),
+ getOAuth2TokenUsingPasswordCredentials: jest.fn(),
+ getOAuth2TokenUsingImplicitGrant: jest.fn(),
+ updateCollectionOauth2Credentials: jest.fn(),
+ clearOauth2CredentialsByCredentialsId: jest.fn()
+}));
+
+jest.mock('../../src/ipc/network/cert-utils', () => ({
+ getCertsAndProxyConfig: jest.fn().mockResolvedValue({}),
+ buildCertsAndProxyConfig: jest.fn()
+}));
+
const { configureRequest } = require('../../src/ipc/network/index');
+const { getOAuth2TokenUsingClientCredentials } = require('../../src/utils/oauth2');
describe('index: configureRequest', () => {
it('Should add \'http://\' to the URL if no protocol is specified', async () => {
@@ -12,4 +27,35 @@ describe('index: configureRequest', () => {
await configureRequest(null, {}, request, null, null, null, null);
expect(request.url).toEqual('ftp://test-domain');
});
+
+ it('Should not add the OAuth2 token to headers or URL if tokenPlacement is none', async () => {
+ getOAuth2TokenUsingClientCredentials.mockResolvedValue({
+ credentials: { access_token: 'test-token' },
+ url: 'https://auth.example.com/token',
+ credentialsId: 'credentials',
+ debugInfo: {}
+ });
+
+ const request = {
+ method: 'GET',
+ url: 'https://api.example.com/users?existing=1',
+ headers: {},
+ body: {},
+ oauth2: {
+ grantType: 'client_credentials',
+ accessTokenUrl: 'https://auth.example.com/token',
+ clientId: 'client-id',
+ clientSecret: 'client-secret',
+ tokenPlacement: 'none',
+ tokenHeaderPrefix: 'Bearer',
+ tokenQueryKey: 'access_token'
+ }
+ };
+
+ await configureRequest('collection-uid', { promptVariables: {} }, request, {}, {}, {}, null, {});
+
+ expect(request.headers.Authorization).toBeUndefined();
+ expect(request.url).toEqual('https://api.example.com/users?existing=1');
+ expect(request.oauth2Credentials.credentials.access_token).toBe('test-token');
+ });
});
diff --git a/packages/bruno-electron/tests/network/prepare-grpc-request.spec.js b/packages/bruno-electron/tests/network/prepare-grpc-request.spec.js
index 161d40218f5..f66d2cefaf2 100644
--- a/packages/bruno-electron/tests/network/prepare-grpc-request.spec.js
+++ b/packages/bruno-electron/tests/network/prepare-grpc-request.spec.js
@@ -2,15 +2,19 @@ const { describe, it, expect, beforeEach } = require('@jest/globals');
// Mock dependencies
jest.mock('../../src/ipc/network/interpolate-vars');
+jest.mock('../../src/ipc/network/cert-utils');
jest.mock('../../src/utils/collection');
jest.mock('../../src/store/process-env');
jest.mock('../../src/utils/oauth2');
jest.mock('../../src/ipc/network/prepare-request');
const prepareGrpcRequest = require('../../src/ipc/network/prepare-grpc-request');
+const { configureRequest } = require('../../src/ipc/network/prepare-grpc-request');
const interpolateVars = require('../../src/ipc/network/interpolate-vars');
+const { getCertsAndProxyConfig } = require('../../src/ipc/network/cert-utils');
const { getEnvVars, getTreePathFromCollectionToItem } = require('../../src/utils/collection');
const { getProcessEnvVars } = require('../../src/store/process-env');
+const { getOAuth2TokenUsingClientCredentials } = require('../../src/utils/oauth2');
const { setAuthHeaders } = require('../../src/ipc/network/prepare-request');
describe('prepare-grpc-request: prepareGrpcRequest', () => {
@@ -25,7 +29,17 @@ describe('prepare-grpc-request: prepareGrpcRequest', () => {
getEnvVars.mockReturnValue({});
getTreePathFromCollectionToItem.mockReturnValue([]);
getProcessEnvVars.mockReturnValue({});
- setAuthHeaders.mockImplementation((request) => request);
+ getCertsAndProxyConfig.mockResolvedValue({});
+ setAuthHeaders.mockImplementation((grpcRequest, request) => {
+ if (request?.auth?.mode === 'oauth2') {
+ return {
+ ...grpcRequest,
+ oauth2: request.auth.oauth2
+ };
+ }
+
+ return grpcRequest;
+ });
interpolateVars.mockImplementation((request) => request);
mockItem = {
@@ -90,5 +104,46 @@ describe('prepare-grpc-request: prepareGrpcRequest', () => {
expect(result.headers).toEqual({});
});
+
+ it('should not add the OAuth2 token when tokenPlacement is none', async () => {
+ getOAuth2TokenUsingClientCredentials.mockResolvedValue({
+ credentials: { access_token: 'token123' },
+ url: 'https://auth.example.com/token',
+ credentialsId: 'credentials',
+ debugInfo: {}
+ });
+
+ mockItem.request.url = 'grpc://localhost:50051?existing=1';
+ mockItem.request.headers = [];
+ mockItem.request.auth = {
+ mode: 'oauth2',
+ oauth2: {
+ grantType: 'client_credentials',
+ accessTokenUrl: 'https://auth.example.com/token',
+ clientId: 'client-id',
+ clientSecret: 'client-secret',
+ tokenPlacement: 'none',
+ tokenHeaderPrefix: 'Bearer',
+ tokenQueryKey: 'access_token'
+ }
+ };
+
+ const result = await prepareGrpcRequest(mockItem, mockCollection, mockEnvironment, mockRuntimeVariables);
+
+ await configureRequest(
+ result,
+ mockItem.request,
+ mockCollection,
+ result.envVars,
+ mockRuntimeVariables,
+ result.processEnvVars,
+ result.promptVariables,
+ {}
+ );
+
+ expect(result.headers['Authorization']).toBeUndefined();
+ expect(result.url).toBe('grpc://localhost:50051?existing=1');
+ expect(result.oauth2Credentials.credentials.access_token).toBe('token123');
+ });
});
});
diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js
index de35e01d14d..824f3cb9096 100644
--- a/packages/bruno-lang/v2/src/jsonToBru.js
+++ b/packages/bruno-lang/v2/src/jsonToBru.js
@@ -293,7 +293,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ (auth?.oauth2?.tokenPlacement === 'url' || auth?.oauth2?.tokenPlacement === 'query') ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
@@ -319,7 +319,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ auth?.oauth2?.tokenPlacement == 'url' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
@@ -341,7 +341,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ auth?.oauth2?.tokenPlacement == 'url' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
@@ -362,7 +362,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ auth?.oauth2?.tokenPlacement == 'url' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
}
diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js
index 0376f6697b0..665943cef86 100644
--- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js
+++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js
@@ -182,7 +182,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ (auth?.oauth2?.tokenPlacement === 'url' || auth?.oauth2?.tokenPlacement === 'query') ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
@@ -208,7 +208,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ auth?.oauth2?.tokenPlacement == 'url' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
@@ -229,7 +229,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ auth?.oauth2?.tokenPlacement == 'url' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
}
@@ -250,7 +250,7 @@ ${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
- auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
+ auth?.oauth2?.tokenPlacement == 'url' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
diff --git a/packages/bruno-lang/v2/tests/jsonToBru.spec.js b/packages/bruno-lang/v2/tests/jsonToBru.spec.js
index 0591464699b..01c660ad170 100644
--- a/packages/bruno-lang/v2/tests/jsonToBru.spec.js
+++ b/packages/bruno-lang/v2/tests/jsonToBru.spec.js
@@ -136,4 +136,42 @@ describe('jsonToBru stringify', () => {
`);
});
});
+
+ describe('oauth2 token placement', () => {
+ it('omits token placement fields when tokenPlacement is none', () => {
+ const input = {
+ meta: {
+ name: 'oauth2-none',
+ type: 'http',
+ seq: 1
+ },
+ http: {
+ method: 'get',
+ url: 'https://api.example.com/users',
+ body: 'none',
+ auth: 'oauth2'
+ },
+ auth: {
+ mode: 'oauth2',
+ oauth2: {
+ grantType: 'client_credentials',
+ accessTokenUrl: 'https://auth.example.com/token',
+ clientId: 'client-id',
+ clientSecret: 'client-secret',
+ credentialsPlacement: 'body',
+ credentialsId: 'credentials',
+ tokenPlacement: 'none',
+ tokenHeaderPrefix: 'Bearer',
+ tokenQueryKey: 'access_token'
+ }
+ }
+ };
+
+ const output = stringify(input);
+
+ expect(output).toContain('token_placement: none');
+ expect(output).not.toContain('token_header_prefix:');
+ expect(output).not.toContain('token_query_key:');
+ });
+ });
});