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 b9b6f66bc..20c4923cd 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 @@ -11,7 +11,6 @@ import Table from "components/Table/index"; const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); - const [activeTab, setActiveTab] = useState('authorization'); const oAuth = get(request, 'auth.oauth2', {}); const { @@ -19,6 +18,8 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { additionalParameters = {} } = oAuth; + const [activeTab, setActiveTab] = useState(grantType == 'authorization_code' ? 'authorization' : 'token'); + const isEmptyParam = (param) => { return !param.name.trim() && !param.value.trim(); }; @@ -28,8 +29,8 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { return tabParams.some(isEmptyParam); }; - const updateAdditionalParams = ({ updatedAdditionalParams }) => { - const filteredParams = cloneDeep(updatedAdditionalParams); + const updateAdditionalParameters = ({ updatedAdditionalParameters }) => { + const filteredParams = cloneDeep(updatedAdditionalParameters); Object.keys(filteredParams).forEach(paramType => { if (filteredParams[paramType]?.length) { @@ -60,14 +61,14 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { } const handleUpdateAdditionalParam = ({ paramType, key, paramIndex, value }) => { - const updatedAdditionalParams = cloneDeep(additionalParameters); + const updatedAdditionalParameters = cloneDeep(additionalParameters); - if (!updatedAdditionalParams[paramType]) { - updatedAdditionalParams[paramType] = []; + if (!updatedAdditionalParameters[paramType]) { + updatedAdditionalParameters[paramType] = []; } - if (!updatedAdditionalParams[paramType][paramIndex]) { - updatedAdditionalParams[paramType][paramIndex] = { + if (!updatedAdditionalParameters[paramType][paramIndex]) { + updatedAdditionalParameters[paramType][paramIndex] = { name: '', value: '', sendIn: 'headers', @@ -75,25 +76,25 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { }; } - updatedAdditionalParams[paramType][paramIndex][key] = value; + updatedAdditionalParameters[paramType][paramIndex][key] = value; // Only filter when updating a parameter - updateAdditionalParams({ updatedAdditionalParams }); + updateAdditionalParameters({ updatedAdditionalParameters }); } const handleDeleteAdditionalParam = ({ paramType, paramIndex }) => { - const updatedAdditionalParams = cloneDeep(additionalParameters); + const updatedAdditionalParameters = cloneDeep(additionalParameters); - if (updatedAdditionalParams[paramType]?.length) { - updatedAdditionalParams[paramType] = updatedAdditionalParams[paramType].filter((_, index) => index !== paramIndex); + if (updatedAdditionalParameters[paramType]?.length) { + updatedAdditionalParameters[paramType] = updatedAdditionalParameters[paramType].filter((_, index) => index !== paramIndex); // If the array is now empty, ensure we're not sending empty arrays - if (updatedAdditionalParams[paramType].length === 0) { - delete updatedAdditionalParams[paramType]; + if (updatedAdditionalParameters[paramType].length === 0) { + delete updatedAdditionalParameters[paramType]; } } - updateAdditionalParams({ updatedAdditionalParams }); + updateAdditionalParameters({ updatedAdditionalParameters }); } const handleAddNewAdditionalParam = () => { @@ -149,7 +150,7 @@ const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => {
-
setActiveTab('authorization')}>Authorization
+ {grantType == 'authorization_code' &&
setActiveTab('authorization')}>Authorization
}
setActiveTab('token')}>Token
setActiveTab('refresh')}>Refresh
@@ -279,12 +280,10 @@ const sendInOptionsMap = { 'refresh': ['headers', 'queryparams', 'body'] }, 'password': { - 'authorization': ['headers', 'queryparams'], 'token': ['headers', 'queryparams', 'body'], 'refresh': ['headers', 'queryparams', 'body'] }, 'client_credentials': { - 'authorization': ['headers', 'queryparams'], 'token': ['headers', 'queryparams', 'body'], 'refresh': ['headers', 'queryparams', 'body'] } diff --git a/packages/bruno-app/src/components/ResponsePane/Timeline/TimelineItem/Request/index.js b/packages/bruno-app/src/components/ResponsePane/Timeline/TimelineItem/Request/index.js index 1cef8e9e5..a1d4cca22 100644 --- a/packages/bruno-app/src/components/ResponsePane/Timeline/TimelineItem/Request/index.js +++ b/packages/bruno-app/src/components/ResponsePane/Timeline/TimelineItem/Request/index.js @@ -26,7 +26,7 @@ const Request = ({ collection, request, item, width }) => {
{/* Method and URL */}
-
{url}
+
{url}
{/* Headers */} diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 749e32a6d..686182ee6 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -87,7 +87,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), - autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken') + autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), + additionalParameters: get(collectionAuth, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; case 'authorization_code': @@ -108,7 +109,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), - autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken') + autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), + additionalParameters: get(collectionAuth, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; case 'client_credentials': @@ -125,7 +127,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), - autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken') + autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), + additionalParameters: get(collectionAuth, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; } @@ -185,7 +188,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), - autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken') + autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken'), + additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; case 'authorization_code': @@ -206,7 +210,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), - autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken') + autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken'), + additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; case 'client_credentials': @@ -223,7 +228,8 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), - autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken') + autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken'), + additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; break; } diff --git a/packages/bruno-electron/src/utils/oauth2.js b/packages/bruno-electron/src/utils/oauth2.js index 50b1f73ed..24cc2bfed 100644 --- a/packages/bruno-electron/src/utils/oauth2.js +++ b/packages/bruno-electron/src/utils/oauth2.js @@ -142,13 +142,13 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo data.scope = scope; } + requestCopy.url = url; // Apply additional parameters to token request if (additionalParameters?.token?.length) { applyAdditionalParameters(requestCopy, data, additionalParameters.token); } requestCopy.data = qs.stringify(data); - requestCopy.url = url; requestCopy.responseType = 'arraybuffer'; // Initialize variables to hold request and response data for debugging @@ -400,12 +400,13 @@ const getOAuth2TokenUsingClientCredentials = async ({ request, collectionUid, fo if (scope) { data.scope = scope; } + + requestCopy.url = url; if (additionalParameters?.token?.length) { applyAdditionalParameters(requestCopy, data, additionalParameters.token); } requestCopy.data = qs.stringify(data); - requestCopy.url = url; requestCopy.responseType = 'arraybuffer'; // Initialize variables to hold request and response data for debugging @@ -593,12 +594,13 @@ const getOAuth2TokenUsingPasswordCredentials = async ({ request, collectionUid, if (scope) { data.scope = scope; } + + requestCopy.url = url; if (additionalParameters?.token?.length) { applyAdditionalParameters(requestCopy, data, additionalParameters.token); } requestCopy.data = qs.stringify(data); - requestCopy.url = url; requestCopy.responseType = 'arraybuffer'; // Initialize variables to hold request and response data for debugging @@ -714,6 +716,8 @@ const refreshOauth2Token = async ({ requestCopy, collectionUid, certsAndProxyCon if (clientSecret) { data.client_secret = clientSecret; } + + requestCopy.url = url; if (oAuth.additionalParameters?.refresh?.length) { applyAdditionalParameters(requestCopy, data, oAuth.additionalParameters.refresh); } @@ -722,7 +726,6 @@ const refreshOauth2Token = async ({ requestCopy, collectionUid, certsAndProxyCon requestCopy.headers['content-type'] = 'application/x-www-form-urlencoded'; requestCopy.headers['Accept'] = 'application/json'; requestCopy.data = qs.stringify(data); - requestCopy.url = url; requestCopy.responseType = 'arraybuffer'; // Initialize variables to hold request and response data for debugging @@ -845,11 +848,7 @@ const generateCodeChallenge = (codeVerifier) => { }; // Apply additional parameters to a request -const applyAdditionalParameters = (requestCopy, data, params) => { - if (!params || !params.length) { - return; - } - +const applyAdditionalParameters = (requestCopy, data, params = []) => { params.forEach(param => { if (!param.enabled || !param.name) { return; @@ -861,12 +860,14 @@ const applyAdditionalParameters = (requestCopy, data, params) => { break; case 'queryparams': // For query params, add to URL - if (!requestCopy.url.includes('?')) { - requestCopy.url += '?'; - } else if (!requestCopy.url.endsWith('&') && !requestCopy.url.endsWith('?')) { - requestCopy.url += '&'; + try { + let url = new URL(requestCopy.url); + url.searchParams.append(param.name, param.value); + requestCopy.url = url.href; + } + catch (error) { + console.error('invalid token/refresh url', requestCopy.url); } - requestCopy.url += `${encodeURIComponent(param.name)}=${encodeURIComponent(param.value || '')}`; break; case 'body': // For body, add to data object diff --git a/packages/bruno-lang/v2/src/utils.js b/packages/bruno-lang/v2/src/utils.js index 64d377aee..aaef783c4 100644 --- a/packages/bruno-lang/v2/src/utils.js +++ b/packages/bruno-lang/v2/src/utils.js @@ -40,19 +40,21 @@ const mergeOauth2AdditionalParameters = (ast) => { const refreshQueryParams = ast?.oauth2_additional_parameters_refresh_queryparams; const refreshBodyValues = ast?.oauth2_additional_parameters_refresh_bodyvalues; - if (authorizationHeaders?.length || authorizationQueryParams?.length) { - additionalParameters['authorization'] = [] - } - if (authorizationHeaders?.length) { - additionalParameters['authorization'] = [ - ...authorizationHeaders?.map(_ => ({ ..._, sendIn: 'headers' })) - ] - } - if (authorizationQueryParams?.length) { - additionalParameters['authorization'] = [ - ...additionalParameters['authorization'] || [], - ...authorizationQueryParams?.map(_ => ({ ..._, sendIn: 'queryparams' })) - ] + if (ast?.auth?.oauth2?.grantType == 'authorization_code') { + if (authorizationHeaders?.length || authorizationQueryParams?.length) { + additionalParameters['authorization'] = [] + } + if (authorizationHeaders?.length) { + additionalParameters['authorization'] = [ + ...authorizationHeaders?.map(_ => ({ ..._, sendIn: 'headers' })) + ] + } + if (authorizationQueryParams?.length) { + additionalParameters['authorization'] = [ + ...additionalParameters['authorization'] || [], + ...authorizationQueryParams?.map(_ => ({ ..._, sendIn: 'queryparams' })) + ] + } } if (tokenHeaders?.length || tokenQueryParams?.length || tokenBodyValues?.length) { diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 253d644cd..936eee680 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -276,7 +276,11 @@ const oauth2Schema = Yup.object({ otherwise: Yup.boolean() }), additionalParameters: Yup.object({ - authorization: Yup.array().of(oauth2AuthorizationAdditionalParametersSchema).optional(), + authorization: Yup.mixed().when('grantType', { + is: 'authorization_code', + then: Yup.array().of(oauth2AuthorizationAdditionalParametersSchema).required(), + otherwise: Yup.mixed().nullable().optional() + }), token: Yup.array().of(oauth2AdditionalParametersSchema).optional(), refresh: Yup.array().of(oauth2AdditionalParametersSchema).optional() })