additional params updates

This commit is contained in:
lohit-bruno
2025-08-13 21:42:04 +05:30
parent 7ccbea7ced
commit ceab0b4dc1
15 changed files with 780 additions and 93 deletions

View File

@@ -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) => (
<div
key={tabKey}
className={`tab ${activeTab === tabKey ? 'active' : ''}`}
onClick={() => setActiveTab(tabKey)}
>
{tabLabel}
</div>
);
return (
<StyledWrapper className="mt-4">
<div className="flex items-center gap-2.5 mb-3">
@@ -150,9 +175,9 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => {
</div>
<div className="tabs flex w-full gap-2 my-2">
{grantType == 'authorization_code' && <div className={`tab ${activeTab == 'authorization' ? 'active': ''}`} onClick={e => setActiveTab('authorization')}>Authorization</div>}
<div className={`tab ${activeTab == 'token' ? 'active': ''}`} onClick={e => setActiveTab('token')}>Token</div>
<div className={`tab ${activeTab == 'refresh' ? 'active': ''}`} onClick={e => setActiveTab('refresh')}>Refresh</div>
{availableTabs.includes('authorization') && renderTab('authorization', 'Authorization')}
{availableTabs.includes('token') && renderTab('token', 'Token')}
{availableTabs.includes('refresh') && renderTab('refresh', 'Refresh')}
</div>
<Table
headers={[
@@ -286,5 +311,8 @@ const sendInOptionsMap = {
'client_credentials': {
'token': ['headers', 'queryparams', 'body'],
'refresh': ['headers', 'queryparams', 'body']
},
'implicit': {
'authorization': ['headers', 'queryparams']
}
}

View File

@@ -1,16 +1,15 @@
import React, { useRef, forwardRef, useState, useMemo } from 'react';
import React, { useRef, forwardRef, useMemo } from 'react';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import { IconCaretDown, IconLoader2, IconSettings, IconKey, IconHelp, IconAdjustmentsHorizontal } from '@tabler/icons';
import { IconCaretDown, IconSettings, IconKey, IconHelp, IconAdjustmentsHorizontal } from '@tabler/icons';
import Dropdown from 'components/Dropdown';
import SingleLineEditor from 'components/SingleLineEditor';
import { clearOauth2Cache, fetchOauth2Credentials } from 'providers/ReduxStore/slices/collections/actions';
import Wrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import toast from 'react-hot-toast';
import Oauth2TokenViewer from '../Oauth2TokenViewer/index';
import { cloneDeep } from 'lodash';
import Oauth2ActionButtons from '../Oauth2ActionButtons/index';
import AdditionalParams from '../AdditionalParams/index';
import { getAllVariables } from 'utils/collections/index';
import { interpolate } from '@usebruno/common';
@@ -19,7 +18,6 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle
const { storedTheme } = useTheme();
const dropdownTippyRef = useRef();
const onDropdownCreate = (ref) => (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 (
<Wrapper className="mt-2 flex w-full gap-4 flex-col">
<Oauth2TokenViewer handleRun={handleRun} collection={collection} item={item} url={authorizationUrl} credentialsId={credentialsId} />
@@ -262,18 +218,13 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle
</div>
</div>
<div className="flex flex-row gap-4 mt-4">
<button
onClick={handleFetchOauth2Credentials}
className={`submit btn btn-sm btn-secondary w-fit flex flex-row`}
disabled={fetchingToken}
>
Get Access Token{fetchingToken ? <IconLoader2 className="animate-spin ml-2" size={18} strokeWidth={1.5} /> : ""}
</button>
<button onClick={handleClearCache} className="submit btn btn-sm btn-secondary w-fit">
Clear Cache
</button>
</div>
<AdditionalParams
item={item}
request={request}
collection={collection}
updateAuth={updateAuth}
/>
<Oauth2ActionButtons item={item} request={request} collection={collection} url={interpolatedAuthUrl} credentialsId={credentialsId} />
</Wrapper>
);
};

View File

@@ -99,12 +99,22 @@ const Oauth2ActionButtons = ({ item, request, collection, url: accessTokenUrl, c
return (
<div className="flex flex-row gap-4 mt-4">
<button onClick={handleFetchOauth2Credentials} className={`submit btn btn-sm btn-secondary w-fit flex flex-row`}>
<button
onClick={handleFetchOauth2Credentials}
className={`submit btn btn-sm btn-secondary w-fit flex flex-row`}
disabled={fetchingToken || refreshingToken}
>
Get Access Token{fetchingToken? <IconLoader2 className="animate-spin ml-2" size={18} strokeWidth={1.5} /> : ""}
</button>
{creds?.refresh_token ? <button onClick={handleRefreshAccessToken} className={`submit btn btn-sm btn-secondary w-fit flex flex-row`}>
Refresh Token{refreshingToken? <IconLoader2 className="animate-spin ml-2" size={18} strokeWidth={1.5} /> : ""}
</button> : null}
{creds?.refresh_token ?
<button
onClick={handleRefreshAccessToken}
className={`submit btn btn-sm btn-secondary w-fit flex flex-row`}
disabled={fetchingToken || refreshingToken}
>
Refresh Token{refreshingToken? <IconLoader2 className="animate-spin ml-2" size={18} strokeWidth={1.5} /> : ""}
</button>
: null}
<button onClick={handleClearCache} className="submit btn btn-sm btn-secondary w-fit">
Clear Cache
</button>

View File

@@ -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

View File

@@ -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':

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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
};

View File

@@ -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']);
});
});

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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);

View File

@@ -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')
)}
}
`;
}
}

View File

@@ -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')
)}
}
`;
}
}

View File

@@ -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
}]);
});
});