diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js index 20c4923cd..0069c5203 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js @@ -18,7 +18,9 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { additionalParameters = {} } = oAuth; - const [activeTab, setActiveTab] = useState(grantType == 'authorization_code' ? 'authorization' : 'token'); + const [activeTab, setActiveTab] = useState( + (grantType == 'authorization_code' || grantType == 'implicit') ? 'authorization' : 'token' + ); const isEmptyParam = (param) => { return !param.name.trim() && !param.value.trim(); @@ -138,6 +140,29 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { // Add a class to the Add Parameter button if it's disabled const addButtonDisabled = hasEmptyRow(); + // Define available tabs for each grant type + const getAvailableTabs = (grantType) => { + const tabConfig = { + 'authorization_code': ['authorization', 'token', 'refresh'], + 'implicit': ['authorization'], + 'password': ['token', 'refresh'], + 'client_credentials': ['token', 'refresh'] + }; + return tabConfig[grantType] || ['token', 'refresh']; + }; + + const availableTabs = getAvailableTabs(grantType); + + const renderTab = (tabKey, tabLabel) => ( +
setActiveTab(tabKey)} + > + {tabLabel} +
+ ); + return (
@@ -150,9 +175,9 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => {
- {grantType == 'authorization_code' &&
setActiveTab('authorization')}>Authorization
} -
setActiveTab('token')}>Token
-
setActiveTab('refresh')}>Refresh
+ {availableTabs.includes('authorization') && renderTab('authorization', 'Authorization')} + {availableTabs.includes('token') && renderTab('token', 'Token')} + {availableTabs.includes('refresh') && renderTab('refresh', 'Refresh')}
(dropdownTippyRef.current = ref); - const [fetchingToken, toggleFetchingToken] = useState(false); const oAuth = get(request, 'auth.oauth2', {}); const { @@ -49,38 +47,6 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle ); }); - const handleFetchOauth2Credentials = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleFetchingToken(true); - try { - const result = await dispatch(fetchOauth2Credentials({ - itemUid: item.uid, - request: requestCopy, - collection, - folderUid: folder?.uid || null, - forceGetToken: true - })); - - toggleFetchingToken(false); - - // Check if the result contains error or if access_token is missing - if (result?.error || !result?.access_token) { - const errorMessage = result?.error || 'No access token received from authorization server'; - toast.error(errorMessage); - return; - } - - toast.success('Token fetched successfully!'); - } - catch (error) { - console.error(error); - toggleFetchingToken(false); - toast.error(error?.message || 'An error occurred while fetching token!'); - } - } - const handleSave = () => { save(); }; const handleChange = (key, value) => { @@ -111,16 +77,6 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle handleChange('autoFetchToken', e.target.checked); }; - const handleClearCache = (e) => { - dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: interpolatedAuthUrl, credentialsId })) - .then(() => { - toast.success('Cleared cache successfully'); - }) - .catch((err) => { - toast.error(err.message); - }); - }; - return ( @@ -262,18 +218,13 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle -
- - -
+ +
); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js index de729fdd5..3d3dc697d 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js @@ -99,12 +99,22 @@ const Oauth2ActionButtons = ({ item, request, collection, url: accessTokenUrl, c return (
- - {creds?.refresh_token ? : null} + {creds?.refresh_token ? + + : null} diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index 5d80cf567..34833e041 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -235,6 +235,39 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc default: break; } + + // Interpolate additional parameters for all OAuth2 grant types + if (request.oauth2.additionalParameters) { + // Interpolate authorization parameters + if (Array.isArray(request.oauth2.additionalParameters.authorization)) { + request.oauth2.additionalParameters.authorization.forEach(param => { + if (param && param.enabled !== false) { + param.name = _interpolate(param.name) || ''; + param.value = _interpolate(param.value) || ''; + } + }); + } + + // Interpolate token parameters + if (Array.isArray(request.oauth2.additionalParameters.token)) { + request.oauth2.additionalParameters.token.forEach(param => { + if (param && param.enabled !== false) { + param.name = _interpolate(param.name) || ''; + param.value = _interpolate(param.value) || ''; + } + }); + } + + // Interpolate refresh parameters + if (Array.isArray(request.oauth2.additionalParameters.refresh)) { + request.oauth2.additionalParameters.refresh.forEach(param => { + if (param && param.enabled !== false) { + param.name = _interpolate(param.name) || ''; + param.value = _interpolate(param.value) || ''; + } + }); + } + } } // interpolate vars for aws sigv4 auth diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index f5510a4aa..7bdb94a32 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -126,7 +126,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(collectionAuth, 'oauth2.tokenPlacement'), tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), - autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken') + autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), + additionalParameters: get(collectionAuth, 'oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; case 'client_credentials': @@ -242,7 +243,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(request, 'auth.oauth2.tokenPlacement'), tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), - autoFetchToken: get(request, 'auth.oauth2.autoFetchToken') + autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), + additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; case 'client_credentials': diff --git a/packages/bruno-electron/src/utils/oauth2.js b/packages/bruno-electron/src/utils/oauth2.js index 45b776097..072b36b08 100644 --- a/packages/bruno-electron/src/utils/oauth2.js +++ b/packages/bruno-electron/src/utils/oauth2.js @@ -638,7 +638,7 @@ const getOAuth2TokenUsingPasswordCredentials = async ({ request, collectionUid, const refreshOauth2Token = async ({ requestCopy, collectionUid, certsAndProxyConfig }) => { const oAuth = get(requestCopy, 'oauth2', {}); - const { clientId, clientSecret, credentialsId } = oAuth; + const { clientId, clientSecret, credentialsId, additionalParameters } = oAuth; const url = oAuth.refreshTokenUrl ? oAuth.refreshTokenUrl : oAuth.accessTokenUrl; const credentials = getStoredOauth2Credentials({ collectionUid, url, credentialsId }); @@ -663,8 +663,8 @@ const refreshOauth2Token = async ({ requestCopy, collectionUid, certsAndProxyCon }; axiosRequestConfig.url = url; axiosRequestConfig.responseType = 'arraybuffer'; - if (oAuth.additionalParameters?.refresh?.length) { - applyAdditionalParameters(axiosRequestConfig, data, oAuth.additionalParameters.refresh); + if (additionalParameters?.refresh?.length) { + applyAdditionalParameters(axiosRequestConfig, data, additionalParameters.refresh); } axiosRequestConfig.data = qs.stringify(data); let debugInfo = { data: [] }; @@ -740,7 +740,8 @@ const getOAuth2TokenUsingImplicitGrant = async ({ request, collectionUid, forceF state = '', callbackUrl, credentialsId = 'credentials', - autoFetchToken = true + autoFetchToken = true, + additionalParameters } = oauth2; // Validate required fields @@ -825,6 +826,15 @@ const getOAuth2TokenUsingImplicitGrant = async ({ request, collectionUid, forceF if (state) { authorizationUrlWithQueryParams.searchParams.append('state', state); } + if (additionalParameters?.authorization?.length) { + additionalParameters.authorization.forEach(param => { + if (param.enabled && param.name) { + if (param.sendIn === 'queryparams') { + authorizationUrlWithQueryParams.searchParams.append(param.name, param.value || ''); + } + } + }); + } const authorizeUrl = authorizationUrlWithQueryParams.toString(); @@ -833,7 +843,8 @@ const getOAuth2TokenUsingImplicitGrant = async ({ request, collectionUid, forceF authorizeUrl, callbackUrl, session: oauth2Store.getSessionIdOfCollection({ collectionUid, url: authorizationUrl }), - grantType: 'implicit' + grantType: 'implicit', + additionalHeaders: getAdditionalHeaders(additionalParameters?.authorization) }); if (!implicitTokens || !implicitTokens.access_token) { diff --git a/packages/bruno-filestore/src/formats/bru/index.ts b/packages/bruno-filestore/src/formats/bru/index.ts index e71017cdf..4647c0c60 100644 --- a/packages/bruno-filestore/src/formats/bru/index.ts +++ b/packages/bruno-filestore/src/formats/bru/index.ts @@ -7,6 +7,7 @@ import { collectionBruToJson as _collectionBruToJson, jsonToCollectionBru as _jsonToCollectionBru } from '@usebruno/lang'; +import { getOauth2AdditionalParameters } from './utils/oauth2-additional-params'; export const bruRequestToJson = (data: string | any, parsed: boolean = false): any => { try { @@ -46,6 +47,16 @@ export const bruRequestToJson = (data: string | any, parsed: boolean = false): a transformedJson.request.auth.mode = _.get(json, 'http.auth', 'none'); transformedJson.request.body.mode = _.get(json, 'http.body', 'none'); + // add oauth2 additional parameters if they exist + const hasOauth2GrantType = json?.auth?.oauth2?.grantType; + if (hasOauth2GrantType) { + const additionalParameters = getOauth2AdditionalParameters(json); + const hasAdditionalParameters = Object.keys(additionalParameters || {}).length > 0; + if (hasAdditionalParameters) { + transformedJson.request.auth.oauth2.additionalParameters = additionalParameters; + } + } + return transformedJson; } catch (e) { return Promise.reject(e); @@ -129,6 +140,16 @@ export const bruCollectionToJson = (data: string | any, parsed: boolean = false) } } + // add oauth2 additional parameters if they exist + const hasOauth2GrantType = json?.auth?.oauth2?.grantType; + if (hasOauth2GrantType) { + const additionalParameters = getOauth2AdditionalParameters(json); + const hasAdditionalParameters = Object.keys(additionalParameters).length > 0; + if (hasAdditionalParameters) { + transformedJson.request.auth.oauth2.additionalParameters = additionalParameters; + } + } + return transformedJson; } catch (error) { return Promise.reject(error); diff --git a/packages/bruno-filestore/src/formats/bru/tests/fixtures/oauth2-additional-params.js b/packages/bruno-filestore/src/formats/bru/tests/fixtures/oauth2-additional-params.js new file mode 100644 index 000000000..0fe31f485 --- /dev/null +++ b/packages/bruno-filestore/src/formats/bru/tests/fixtures/oauth2-additional-params.js @@ -0,0 +1,116 @@ +const getBruJsonWithAdditionalParams = (grantType) => ({ + "meta": { + "name": "OAuth2 Additional Params Test", + "type": "http", + "seq": 1 + }, + "http": { + "method": "get", + "url": "https://api.usebruno.com/protected" + }, + "auth": { + "oauth2": { + "grantType": grantType, + }, + }, + "oauth2_additional_parameters_authorization_headers": [ + { + "name": "auth-header", + "value": "auth-header-value", + "enabled": true + }, + { + "name": "disabled-auth-header", + "value": "disabled-auth-header-value", + "enabled": false + } + ], + "oauth2_additional_parameters_authorization_queryparams": [ + { + "name": "auth-query-param", + "value": "auth-query-param-value", + "enabled": true + }, + { + "name": "disabled-auth-query-param", + "value": "disabled-auth-query-param-value", + "enabled": false + } + ], + "oauth2_additional_parameters_token_headers": [ + { + "name": "token-header", + "value": "token-header-value", + "enabled": true + }, + { + "name": "disabled-token-header", + "value": "disabled-token-header-value", + "enabled": false + } + ], + "oauth2_additional_parameters_token_queryparams": [ + { + "name": "token-query-param", + "value": "token-query-param-value", + "enabled": true + }, + { + "name": "disabled-token-query-param", + "value": "disabled-token-query-param-value", + "enabled": false + } + ], + "oauth2_additional_parameters_token_bodyvalues": [ + { + "name": "token-body", + "value": "token-body-value", + "enabled": true + }, + { + "name": "disabled-token-body", + "value": "disabled-token-body-value", + "enabled": false + } + ], + "oauth2_additional_parameters_refresh_headers": [ + { + "name": "refresh-header", + "value": "refresh-header-value", + "enabled": true + }, + { + "name": "disabled-refresh-header", + "value": "disabled-refresh-header-value", + "enabled": false + } + ], + "oauth2_additional_parameters_refresh_queryparams": [ + { + "name": "refresh-query-param", + "value": "refresh-query-param-value", + "enabled": true + }, + { + "name": "disabled-refresh-query-param", + "value": "disabled-refresh-query-param-value", + "enabled": false + } + ], + "oauth2_additional_parameters_refresh_bodyvalues": [ + { + "name": "refresh-body", + "value": "refresh-body-value", + "enabled": true + }, + { + "name": "disabled-refresh-body", + "value": "disabled-refresh-body-value", + "enabled": false + } + ] +}) + +export { + getBruJsonWithAdditionalParams +}; diff --git a/packages/bruno-filestore/src/formats/bru/tests/oauth2-additional-params.spec.js b/packages/bruno-filestore/src/formats/bru/tests/oauth2-additional-params.spec.js new file mode 100644 index 000000000..751fcc745 --- /dev/null +++ b/packages/bruno-filestore/src/formats/bru/tests/oauth2-additional-params.spec.js @@ -0,0 +1,45 @@ +const { getOauth2AdditionalParameters } = require('../utils/oauth2-additional-params'); +const { bruRequestToJson, bruCollectionToJson } = require('../index'); +const { clientCredentialsBruJson, authorizationCodeBruJson, passwordCredentialsBruJson, implicitBruJson, getBruJsonWithAdditionalParams } = require('./fixtures/oauth2-additional-params'); + +describe('getOauth2AdditionalParameters', () => { + it('authorization_code', () => { + const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('authorization_code')); + expect(additionalParameters.authorization).toHaveLength(4); + expect(additionalParameters.token).toHaveLength(6); + expect(additionalParameters.refresh).toHaveLength(6); + + expect(additionalParameters.authorization.map(p => p.sendIn).sort()).toEqual(['headers', 'headers', 'queryparams', 'queryparams']); + expect(additionalParameters.token.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']); + expect(additionalParameters.refresh.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']); + }); + + it('client_credentials', () => { + const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('client_credentials')); + expect(additionalParameters.authorization).toBeUndefined(); + expect(additionalParameters.token).toHaveLength(6); + expect(additionalParameters.refresh).toHaveLength(6); + + expect(additionalParameters.token.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']); + expect(additionalParameters.refresh.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']); + }); + + it('password', () => { + const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('password')); + expect(additionalParameters.authorization).toBeUndefined(); + expect(additionalParameters.token).toHaveLength(6); + expect(additionalParameters.refresh).toHaveLength(6); + + expect(additionalParameters.token.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']); + expect(additionalParameters.refresh.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']); + }); + + it('implicit', () => { + const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('implicit')); + expect(additionalParameters.authorization).toHaveLength(4); + expect(additionalParameters.token).toBeUndefined(); + expect(additionalParameters.refresh).toBeUndefined(); + + expect(additionalParameters.authorization.map(p => p.sendIn).sort()).toEqual(['headers', 'headers', 'queryparams', 'queryparams']); + }); +}); \ No newline at end of file diff --git a/packages/bruno-filestore/src/formats/bru/utils/oauth2-additional-params.ts b/packages/bruno-filestore/src/formats/bru/utils/oauth2-additional-params.ts new file mode 100644 index 000000000..6bf57cefa --- /dev/null +++ b/packages/bruno-filestore/src/formats/bru/utils/oauth2-additional-params.ts @@ -0,0 +1,141 @@ +type T_Oauth2ParameterType = 'authorization' | 'token' | 'refresh'; +type T_Oauth2ParameterSendInType = 'headers' | 'queryparams' | 'body'; + +export interface T_OAuth2AdditionalParam { + name: string; + value: string; + enabled: boolean; + sendIn: T_Oauth2ParameterSendInType +} + +export interface T_OAuth2AdditionalParameters { + authorization?: T_OAuth2AdditionalParam[]; + token?: T_OAuth2AdditionalParam[]; + refresh?: T_OAuth2AdditionalParam[]; +} + +export interface T_Oauth2Auth { + grantType: string; + additionalParameters?: T_OAuth2AdditionalParameters; +} + +export interface T_BruJson { + auth: { + oauth2: T_Oauth2Auth; + }; + oauth2_additional_parameters_authorization_headers?: any[]; + oauth2_additional_parameters_authorization_queryparams?: any[]; + oauth2_additional_parameters_token_headers?: any[]; + oauth2_additional_parameters_token_queryparams?: any[]; + oauth2_additional_parameters_token_bodyvalues?: any[]; + oauth2_additional_parameters_refresh_headers?: any[]; + oauth2_additional_parameters_refresh_queryparams?: any[]; + oauth2_additional_parameters_refresh_bodyvalues?: any[]; +} + +interface T_Oauth2ParameterMapping { + type: T_Oauth2ParameterType; + sendIn: T_Oauth2ParameterSendInType; + source: keyof T_BruJson; +} + +const PARAMETER_MAPPINGS: T_Oauth2ParameterMapping[] = [ + // Authorization parameters (only for authorization_code grant type) + { type: 'authorization', sendIn: 'headers', source: 'oauth2_additional_parameters_authorization_headers' }, + { type: 'authorization', sendIn: 'queryparams', source: 'oauth2_additional_parameters_authorization_queryparams' }, + + // Token parameters (for all grant types) + { type: 'token', sendIn: 'headers', source: 'oauth2_additional_parameters_token_headers' }, + { type: 'token', sendIn: 'queryparams', source: 'oauth2_additional_parameters_token_queryparams' }, + { type: 'token', sendIn: 'body', source: 'oauth2_additional_parameters_token_bodyvalues' }, + + // Refresh parameters (for grant types that support refresh) + { type: 'refresh', sendIn: 'headers', source: 'oauth2_additional_parameters_refresh_headers' }, + { type: 'refresh', sendIn: 'queryparams', source: 'oauth2_additional_parameters_refresh_queryparams' }, + { type: 'refresh', sendIn: 'body', source: 'oauth2_additional_parameters_refresh_bodyvalues' }, +]; + +/** + * Maps source parameters to T_OAuth2AdditionalParam format + */ +const mapParametersFromSource = (sourceParams: any[], sendIn: T_Oauth2ParameterSendInType): T_OAuth2AdditionalParam[] => { + if (!sourceParams?.length) { + return []; + } + + return sourceParams.map(param => ({ + ...param, + sendIn + })); +}; + +/** + * Checks if a parameter type should be included based on grant type + */ +const shouldIncludeParameterType = (type: T_Oauth2ParameterType, grantType: string): boolean => { + // Authorization parameters are only valid for authorization_code grant type + if (type === 'authorization') { + return grantType === 'authorization_code' || grantType === 'implicit'; + } + + if (type === 'token' || type === 'refresh') { + return grantType !== 'implicit'; + } + + // Token and refresh parameters are valid for all grant types + return true; +}; + +/** + * Collects all parameters for a specific type (authorization, token, or refresh) + */ +const collectParametersForType = ( + json: T_BruJson, + type: T_Oauth2ParameterType, + grantType: string +): T_OAuth2AdditionalParam[] => { + if (!shouldIncludeParameterType(type, grantType)) { + return []; + } + + const relevantMappings = PARAMETER_MAPPINGS.filter(mapping => mapping.type === type); + const allParams: T_OAuth2AdditionalParam[] = []; + + for (const mapping of relevantMappings) { + const sourceParams = json[mapping.source] as any[]; + const mappedParams = mapParametersFromSource(sourceParams, mapping.sendIn); + allParams.push(...mappedParams); + } + + return allParams; +}; + +/** + * This function extracts OAuth2 additional parameters from various sources in the bru json data and organizes + * them into a structured format based on their usage context (authorization, token, refresh). + * + * @param json - json object containing OAuth2 configuration and additional parameters + * @returns OAuth2 additional parameters + */ +export const getOauth2AdditionalParameters = (json: T_BruJson): T_OAuth2AdditionalParameters => { + const grantType = json.auth.oauth2.grantType; + const additionalParameters: T_OAuth2AdditionalParameters = {}; + + try { + // Collect parameters for each type + const parameterTypes: T_Oauth2ParameterType[] = ['authorization', 'token', 'refresh']; + + for (const type of parameterTypes) { + const params = collectParametersForType(json, type, grantType); + if (params.length > 0) { + additionalParameters[type] = params; + } + } + } + catch(error) { + console.error(error); + console.error("Error while getting the oauth2 additional parameters!"); + } + + return additionalParameters; +}; \ No newline at end of file diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 58667a485..7b766c7b7 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -884,8 +884,6 @@ const parser = (input) => { if (match.succeeded()) { let ast = sem(match).ast - ast = mergeOauth2AdditionalParameters(ast); - return ast; } else { throw new Error(match.message); diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index ed7836964..7efd1acbf 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -522,8 +522,6 @@ const parser = (input) => { if (match.succeeded()) { let ast = sem(match).ast; - ast = mergeOauth2AdditionalParameters(ast); - return ast; } else { throw new Error(match.message); diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index d9f405a4f..e226f51e5 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -294,6 +294,7 @@ ${indentString( .join('\n') )} } + `; } const authorizationQueryParams = authorizationParams?.filter(p => p?.sendIn == 'queryparams'); @@ -305,7 +306,8 @@ ${indentString( .map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`) .join('\n') )} -} +} + `; } const tokenHeaders = tokenParams?.filter(p => p?.sendIn == 'headers'); @@ -318,7 +320,7 @@ ${indentString( .join('\n') )} } - + `; } const tokenQueryParams = tokenParams?.filter(p => p?.sendIn == 'queryparams'); @@ -331,7 +333,7 @@ ${indentString( .join('\n') )} } - + `; } const tokenBodyValues = tokenParams?.filter(p => p?.sendIn == 'body'); @@ -344,7 +346,7 @@ ${indentString( .join('\n') )} } - + `; } const refreshHeaders = refreshParams?.filter(p => p?.sendIn == 'headers'); @@ -357,7 +359,7 @@ ${indentString( .join('\n') )} } - + `; } const refreshQueryParams = refreshParams?.filter(p => p?.sendIn == 'queryparams'); @@ -370,7 +372,7 @@ ${indentString( .join('\n') )} } - + `; } const refreshBodyValues = refreshParams?.filter(p => p?.sendIn == 'body'); @@ -383,7 +385,7 @@ ${indentString( .join('\n') )} } - + `; } } diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js index 68b021b06..1af07313b 100644 --- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -247,6 +247,7 @@ ${indentString( .join('\n') )} } + `; } const authorizationQueryParams = authorizationParams?.filter(p => p?.sendIn == 'queryparams'); @@ -258,7 +259,8 @@ ${indentString( .map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`) .join('\n') )} -} +} + `; } const tokenHeaders = tokenParams?.filter(p => p?.sendIn == 'headers'); @@ -271,7 +273,7 @@ ${indentString( .join('\n') )} } - + `; } const tokenQueryParams = tokenParams?.filter(p => p?.sendIn == 'queryparams'); @@ -284,7 +286,7 @@ ${indentString( .join('\n') )} } - + `; } const tokenBodyValues = tokenParams?.filter(p => p?.sendIn == 'body'); @@ -297,7 +299,7 @@ ${indentString( .join('\n') )} } - + `; } const refreshHeaders = refreshParams?.filter(p => p?.sendIn == 'headers'); @@ -310,7 +312,7 @@ ${indentString( .join('\n') )} } - + `; } const refreshQueryParams = refreshParams?.filter(p => p?.sendIn == 'queryparams'); @@ -323,7 +325,7 @@ ${indentString( .join('\n') )} } - + `; } const refreshBodyValues = refreshParams?.filter(p => p?.sendIn == 'body'); @@ -336,7 +338,7 @@ ${indentString( .join('\n') )} } - + `; } } diff --git a/packages/bruno-lang/v2/tests/oauth2-additional-params.spec.js b/packages/bruno-lang/v2/tests/oauth2-additional-params.spec.js new file mode 100644 index 000000000..674582114 --- /dev/null +++ b/packages/bruno-lang/v2/tests/oauth2-additional-params.spec.js @@ -0,0 +1,329 @@ +const bruToJson = require('../src/bruToJson'); +const collectionBruToJson = require('../src/collectionBruToJson'); + +describe('OAuth2 Additional Parameters - request level', () => { + it('should parse all oauth2 additional parameters config types together', () => { + const input = ` +meta { + name: OAuth2 Additional Params Test + type: http +} + +get { + url: https://api.usebruno.com/protected +} + +auth:oauth2 { + grant_type: authorization_code + client_id: bruno-client-id + client_secret: bruno-client-secret + authorization_url: https://auth.usebruno.com/oauth/authorize + access_token_url: https://auth.usebruno.com/oauth/token +} + +auth:oauth2:authorization_headers { + auth-header: auth-header-value + ~disabled-auth-header: disabled-auth-header-value +} + +auth:oauth2:authorization_queryparams { + auth-query-param: auth-query-param-value + ~disabled-auth-query-param: disabled-auth-query-param-value +} + +auth:oauth2:token_headers { + token-header: token-header-value + ~disabled-token-header: disabled-token-header-value +} + +auth:oauth2:token_queryparams { + token-query-param: token-query-param-value + ~disabled-token-query-param: disabled-token-query-param-value +} + +auth:oauth2:token_bodyvalues { + token-body: token-body-value + ~disabled-token-body: disabled-token-body-value +} + +auth:oauth2:refresh_headers { + refresh-header: refresh-header-value + ~disabled-refresh-header: disabled-refresh-header-value +} + +auth:oauth2:refresh_queryparams { + refresh-query-param: refresh-query-param-value + ~disabled-refresh-query-param: disabled-refresh-query-param-value +} + +auth:oauth2:refresh_bodyvalues { + refresh-body: refresh-body-value + ~disabled-refresh-body: disabled-refresh-body-value +} + `.trim(); + + const result = bruToJson(input); + + // Verify all config types are present + expect(result).toHaveProperty('oauth2_additional_parameters_authorization_headers'); + expect(result).toHaveProperty('oauth2_additional_parameters_authorization_queryparams'); + expect(result).toHaveProperty('oauth2_additional_parameters_token_headers'); + expect(result).toHaveProperty('oauth2_additional_parameters_token_queryparams'); + expect(result).toHaveProperty('oauth2_additional_parameters_token_bodyvalues'); + expect(result).toHaveProperty('oauth2_additional_parameters_refresh_headers'); + expect(result).toHaveProperty('oauth2_additional_parameters_refresh_queryparams'); + expect(result).toHaveProperty('oauth2_additional_parameters_refresh_bodyvalues'); + + // Verify each has exactly one parameter + expect(result.oauth2_additional_parameters_authorization_headers).toHaveLength(2); + expect(result.oauth2_additional_parameters_authorization_queryparams).toHaveLength(2); + expect(result.oauth2_additional_parameters_token_headers).toHaveLength(2); + expect(result.oauth2_additional_parameters_token_queryparams).toHaveLength(2); + expect(result.oauth2_additional_parameters_token_bodyvalues).toHaveLength(2); + expect(result.oauth2_additional_parameters_refresh_headers).toHaveLength(2); + expect(result.oauth2_additional_parameters_refresh_queryparams).toHaveLength(2); + expect(result.oauth2_additional_parameters_refresh_bodyvalues).toHaveLength(2); + + // Verify parameter values + expect(result.oauth2_additional_parameters_authorization_headers).toEqual([{ + name: 'auth-header', + value: 'auth-header-value', + enabled: true + }, { + name: 'disabled-auth-header', + value: 'disabled-auth-header-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_authorization_queryparams).toEqual([{ + name: 'auth-query-param', + value: 'auth-query-param-value', + enabled: true + }, { + name: 'disabled-auth-query-param', + value: 'disabled-auth-query-param-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_token_headers).toEqual([{ + name: 'token-header', + value: 'token-header-value', + enabled: true + }, { + name: 'disabled-token-header', + value: 'disabled-token-header-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_token_queryparams).toEqual([{ + name: 'token-query-param', + value: 'token-query-param-value', + enabled: true + }, { + name: 'disabled-token-query-param', + value: 'disabled-token-query-param-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_token_bodyvalues).toEqual([{ + name: 'token-body', + value: 'token-body-value', + enabled: true + }, { + name: 'disabled-token-body', + value: 'disabled-token-body-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_refresh_headers).toEqual([{ + name: 'refresh-header', + value: 'refresh-header-value', + enabled: true + }, { + name: 'disabled-refresh-header', + value: 'disabled-refresh-header-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_refresh_queryparams).toEqual([{ + name: 'refresh-query-param', + value: 'refresh-query-param-value', + enabled: true + }, { + name: 'disabled-refresh-query-param', + value: 'disabled-refresh-query-param-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_refresh_bodyvalues).toEqual([{ + name: 'refresh-body', + value: 'refresh-body-value', + enabled: true + }, { + name: 'disabled-refresh-body', + value: 'disabled-refresh-body-value', + enabled: false + }]); + }); +}); + +describe('OAuth2 Additional Parameters - collection/folder level', () => { + it('should parse all oauth2 additional parameters config types together', () => { + const input = ` +auth { + mode: oauth2 +} + +auth:oauth2 { + grant_type: authorization_code + client_id: bruno-client-id + client_secret: bruno-client-secret + authorization_url: https://auth.usebruno.com/oauth/authorize + access_token_url: https://auth.usebruno.com/oauth/token +} + +auth:oauth2:authorization_headers { + auth-header: auth-header-value + ~disabled-auth-header: disabled-auth-header-value +} + +auth:oauth2:authorization_queryparams { + auth-query-param: auth-query-param-value + ~disabled-auth-query-param: disabled-auth-query-param-value +} + +auth:oauth2:token_headers { + token-header: token-header-value + ~disabled-token-header: disabled-token-header-value +} + +auth:oauth2:token_queryparams { + token-query-param: token-query-param-value + ~disabled-token-query-param: disabled-token-query-param-value +} + +auth:oauth2:token_bodyvalues { + token-body: token-body-value + ~disabled-token-body: disabled-token-body-value +} + +auth:oauth2:refresh_headers { + refresh-header: refresh-header-value + ~disabled-refresh-header: disabled-refresh-header-value +} + +auth:oauth2:refresh_queryparams { + refresh-query-param: refresh-query-param-value + ~disabled-refresh-query-param: disabled-refresh-query-param-value +} + +auth:oauth2:refresh_bodyvalues { + refresh-body: refresh-body-value + ~disabled-refresh-body: disabled-refresh-body-value +} + `.trim(); + + const result = collectionBruToJson(input); + + // Verify all config types are present + expect(result).toHaveProperty('oauth2_additional_parameters_authorization_headers'); + expect(result).toHaveProperty('oauth2_additional_parameters_authorization_queryparams'); + expect(result).toHaveProperty('oauth2_additional_parameters_token_headers'); + expect(result).toHaveProperty('oauth2_additional_parameters_token_queryparams'); + expect(result).toHaveProperty('oauth2_additional_parameters_token_bodyvalues'); + expect(result).toHaveProperty('oauth2_additional_parameters_refresh_headers'); + expect(result).toHaveProperty('oauth2_additional_parameters_refresh_queryparams'); + expect(result).toHaveProperty('oauth2_additional_parameters_refresh_bodyvalues'); + + // Verify each has exactly one parameter + expect(result.oauth2_additional_parameters_authorization_headers).toHaveLength(2); + expect(result.oauth2_additional_parameters_authorization_queryparams).toHaveLength(2); + expect(result.oauth2_additional_parameters_token_headers).toHaveLength(2); + expect(result.oauth2_additional_parameters_token_queryparams).toHaveLength(2); + expect(result.oauth2_additional_parameters_token_bodyvalues).toHaveLength(2); + expect(result.oauth2_additional_parameters_refresh_headers).toHaveLength(2); + expect(result.oauth2_additional_parameters_refresh_queryparams).toHaveLength(2); + expect(result.oauth2_additional_parameters_refresh_bodyvalues).toHaveLength(2); + + // Verify parameter values + expect(result.oauth2_additional_parameters_authorization_headers).toEqual([{ + name: 'auth-header', + value: 'auth-header-value', + enabled: true + }, { + name: 'disabled-auth-header', + value: 'disabled-auth-header-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_authorization_queryparams).toEqual([{ + name: 'auth-query-param', + value: 'auth-query-param-value', + enabled: true + }, { + name: 'disabled-auth-query-param', + value: 'disabled-auth-query-param-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_token_headers).toEqual([{ + name: 'token-header', + value: 'token-header-value', + enabled: true + }, { + name: 'disabled-token-header', + value: 'disabled-token-header-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_token_queryparams).toEqual([{ + name: 'token-query-param', + value: 'token-query-param-value', + enabled: true + }, { + name: 'disabled-token-query-param', + value: 'disabled-token-query-param-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_token_bodyvalues).toEqual([{ + name: 'token-body', + value: 'token-body-value', + enabled: true + }, { + name: 'disabled-token-body', + value: 'disabled-token-body-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_refresh_headers).toEqual([{ + name: 'refresh-header', + value: 'refresh-header-value', + enabled: true + }, { + name: 'disabled-refresh-header', + value: 'disabled-refresh-header-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_refresh_queryparams).toEqual([{ + name: 'refresh-query-param', + value: 'refresh-query-param-value', + enabled: true + }, { + name: 'disabled-refresh-query-param', + value: 'disabled-refresh-query-param-value', + enabled: false + }]); + + expect(result.oauth2_additional_parameters_refresh_bodyvalues).toEqual([{ + name: 'refresh-body', + value: 'refresh-body-value', + enabled: true + }, { + name: 'disabled-refresh-body', + value: 'disabled-refresh-body-value', + enabled: false + }]); + }); +}); \ No newline at end of file