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
new file mode 100644
index 000000000..cdee10a49
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js
@@ -0,0 +1,216 @@
+import { useDispatch } from "react-redux";
+import React, { useRef, forwardRef, useState } from 'react';
+import get from 'lodash/get';
+import { useTheme } from 'providers/Theme';
+import { IconPlus } from '@tabler/icons';
+import Dropdown from 'components/Dropdown';
+import { cloneDeep } from "lodash";
+
+const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => {
+ const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
+ const dropdownTippyRef = useRef();
+ const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
+ const [activeTab, setActiveTab] = useState('authorization');
+
+ const oAuth = get(request, 'auth.oauth2', {});
+ const {
+ grantType,
+ callbackUrl,
+ authorizationUrl,
+ accessTokenUrl,
+ clientId,
+ clientSecret,
+ scope,
+ credentialsPlacement,
+ state,
+ pkce,
+ credentialsId,
+ tokenPlacement,
+ tokenHeaderPrefix,
+ tokenQueryKey,
+ refreshTokenUrl,
+ autoRefreshToken,
+ autoFetchToken,
+ additionalParams = {}
+ } = oAuth;
+
+ const handleUpdateAdditionalParam = ({ paramType, key, paramIndex, value }) => {
+ const updatedAdditionalParams = cloneDeep(additionalParams);
+
+ updatedAdditionalParams[paramType][paramIndex][key] = value;
+
+ dispatch(
+ updateAuth({
+ mode: 'oauth2',
+ collectionUid: collection.uid,
+ itemUid: item.uid,
+ content: {
+ grantType,
+ callbackUrl,
+ authorizationUrl,
+ accessTokenUrl,
+ clientId,
+ clientSecret,
+ state,
+ scope,
+ pkce,
+ credentialsPlacement,
+ credentialsId,
+ tokenPlacement,
+ tokenHeaderPrefix,
+ tokenQueryKey,
+ refreshTokenUrl,
+ autoRefreshToken,
+ autoFetchToken,
+ additionalParams: updatedAdditionalParams,
+ }
+ })
+ );
+ }
+
+ const handleAddNewAdditionalParam = () => {
+ const paramType = activeTab;
+ const updatedAdditionalParams = cloneDeep(additionalParams);
+ if (!updatedAdditionalParams?.[paramType]) {
+ updatedAdditionalParams[paramType] = [];
+ }
+ updatedAdditionalParams[paramType] = [
+ ...updatedAdditionalParams[paramType],
+ {
+ name: '',
+ value: '',
+ sendIn: 'header'
+ }
+ ];
+
+ dispatch(
+ updateAuth({
+ mode: 'oauth2',
+ collectionUid: collection.uid,
+ itemUid: item.uid,
+ content: {
+ grantType,
+ callbackUrl,
+ authorizationUrl,
+ accessTokenUrl,
+ clientId,
+ clientSecret,
+ state,
+ scope,
+ pkce,
+ credentialsPlacement,
+ credentialsId,
+ tokenPlacement,
+ tokenHeaderPrefix,
+ tokenQueryKey,
+ refreshTokenUrl,
+ autoRefreshToken,
+ autoFetchToken,
+ additionalParams: updatedAdditionalParams,
+ }
+ })
+ );
+ }
+ return (
+
+
+
Authorization
+
Token
+
Refresh
+
+
+
+
+ | Key |
+ Value |
+ Send In |
+
+
+
+ {additionalParams?.[activeTab]?.map((param, index) =>
+
+ |
+ handleUpdateAdditionalParam({
+ paramType: activeTab,
+ key: 'name',
+ paramIndex: index,
+ value
+ })}
+ collection={collection}
+ />
+ |
+
+ handleUpdateAdditionalParam({
+ paramType: activeTab,
+ key: 'value',
+ paramIndex: index,
+ value
+ })}
+ collection={collection}
+ />
+ |
+ } placement="bottom-end">
+ {
+ dropdownTippyRef.current.hide();
+ handleUpdateAdditionalParam({
+ paramType: activeTab,
+ key: 'sendIn',
+ paramIndex: index,
+ value: 'header'
+ })
+ }}
+ >
+ Header
+
+ {
+ dropdownTippyRef.current.hide();
+ handleUpdateAdditionalParam({
+ paramType: activeTab,
+ key: 'sendIn',
+ paramIndex: index,
+ value: 'queryparams'
+ })
+ }}
+ >
+ Query Params
+
+ {
+ dropdownTippyRef.current.hide();
+ handleUpdateAdditionalParam({
+ paramType: activeTab,
+ key: 'sendIn',
+ paramIndex: index,
+ value: 'body'
+ })
+ }}
+ >
+ Body
+
+
+
+ )}
+
+
+
+
+
+
+ )
+}
+
+export default AdditionalParams;
\ No newline at end of file
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js
index c00964d82..bc2feb019 100644
--- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js
@@ -9,6 +9,7 @@ import StyledWrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import Oauth2TokenViewer from '../Oauth2TokenViewer/index';
import Oauth2ActionButtons from '../Oauth2ActionButtons/index';
+import AdditionalParams from '../AdditionalParams/index';
const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAuth, collection, folder }) => {
const dispatch = useDispatch();
@@ -326,6 +327,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu
+
);
diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js
index 819272240..7c84c7e8a 100644
--- a/packages/bruno-lang/v2/src/bruToJson.js
+++ b/packages/bruno-lang/v2/src/bruToJson.js
@@ -22,12 +22,18 @@ const { safeParseJson, outdentString } = require('./utils');
*
*/
const grammar = ohm.grammar(`Bru {
- BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)*
+ BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs | authOAuth2Configs)*
auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM | authOAuth2 | authwsse | authapikey
bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
bodyforms = bodyformurlencoded | bodymultipart | bodyfile
params = paramspath | paramsquery
-
+
+ // Oauth2 additional parameters
+ authOAuth2Configs = oAuth2AuthorizationConfig | oAuth2TokenConfig | oAuth2RefreshConfig
+ oAuth2AuthorizationConfig = oAuth2AuthorizationHeaders | oAuth2AuthorizationQueryParams
+ oAuth2TokenConfig = oAuth2TokenHeaders | oAuth2TokenQueryParams | oAuth2TokenBodyValues
+ oAuth2RefreshConfig = oAuth2RefreshHeaders | oAuth2RefreshQueryParams | oAuth2RefreshBodyValues
+
nl = "\\r"? "\\n"
st = " " | "\\t"
stnl = st | nl
@@ -92,6 +98,15 @@ const grammar = ohm.grammar(`Bru {
authwsse = "auth:wsse" dictionary
authapikey = "auth:apikey" dictionary
+ oAuth2AuthorizationHeaders = "auth:oauth2:authorization_headers" dictionary
+ oAuth2AuthorizationQueryParams = "auth:oauth2:authorization_queryparams" dictionary
+ oAuth2TokenHeaders = "auth:oauth2:token_headers" dictionary
+ oAuth2TokenQueryParams = "auth:oauth2:token_queryparams" dictionary
+ oAuth2TokenBodyValues = "auth:oauth2:token_bodyvalues" dictionary
+ oAuth2RefreshHeaders = "auth:oauth2:authorization_headers" dictionary
+ oAuth2RefreshQueryParams = "auth:oauth2:authorization_queryparams" dictionary
+ oAuth2RefreshBodyValues = "auth:oauth2:authorization_bodyvalues" dictionary
+
body = "body" st* "{" nl* textblock tagend
bodyjson = "body:json" st* "{" nl* textblock tagend
bodytext = "body:text" st* "{" nl* textblock tagend
@@ -588,6 +603,146 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}
};
},
+ oAuth2AuthorizationHeaders(_1, dictionary) {
+ const authorizationHeaders = [...mapPairListToKeyValPairs(dictionary.ast)]?.map(_ => ({
+ ..._,
+ sendIn: 'headers'
+ }));
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ authorization: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorization || []),
+ ...authorizationHeaders
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2AuthorizationQueryParams(_1, dictionary) {
+ const authorizationQueryParams = [...mapPairListToKeyValPairs(dictionary.ast)]?.map(_ => ({
+ ..._,
+ sendIn: 'queryparams'
+ }));
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ authorization: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorization || []),
+ ...authorizationQueryParams
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2TokenHeaders(_1, dictionary) {
+ const tokenHeaders = [...mapPairListToKeyValPairs(dictionary.ast)]?.map(_ => ({
+ ..._,
+ sendIn: 'headers'
+ }));
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ token: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.token || []),
+ ...tokenHeaders
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2TokenQueryParams(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ tokenQueryParams: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenQueryParams || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2TokenBodyValues(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ tokenBodyValues: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenBodyValues || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2RefreshHeaders(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ refreshHeaders: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshHeaders || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2RefreshQueryParams(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ refreshQueryParams: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshQueryParams || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2RefreshBodyValues(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ refreshBodyValues: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshBodyValues || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
authwsse(_1, dictionary) {
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
@@ -782,4 +937,4 @@ const parser = (input) => {
};
module.exports = parser;
-
\ No newline at end of file
+
diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js
index 16a0c8d79..4c49fc39f 100644
--- a/packages/bruno-lang/v2/src/collectionBruToJson.js
+++ b/packages/bruno-lang/v2/src/collectionBruToJson.js
@@ -3,9 +3,15 @@ const _ = require('lodash');
const { safeParseJson, outdentString } = require('./utils');
const grammar = ohm.grammar(`Bru {
- BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)*
+ BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs | authOAuth2Configs)*
auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM |authOAuth2 | authwsse | authapikey
+ // Oauth2 additional parameters
+ authOAuth2Configs = oAuth2AuthorizationConfig | oAuth2TokenConfig | oAuth2RefreshConfig
+ oAuth2AuthorizationConfig = oAuth2AuthorizationHeaders | oAuth2AuthorizationQueryParams
+ oAuth2TokenConfig = oAuth2TokenHeaders | oAuth2TokenQueryParams | oAuth2TokenBodyValues
+ oAuth2RefreshConfig = oAuth2RefreshHeaders | oAuth2RefreshQueryParams | oAuth2RefreshBodyValues
+
nl = "\\r"? "\\n"
st = " " | "\\t"
stnl = st | nl
@@ -30,6 +36,15 @@ const grammar = ohm.grammar(`Bru {
auth = "auth" dictionary
+ oAuth2AuthorizationHeaders = "auth:oauth2:authorization_headers" dictionary
+ oAuth2AuthorizationQueryParams = "auth:oauth2:authorization_queryparams" dictionary
+ oAuth2TokenHeaders = "auth:oauth2:token_headers" dictionary
+ oAuth2TokenQueryParams = "auth:oauth2:token_queryparams" dictionary
+ oAuth2TokenBodyValues = "auth:oauth2:token_bodyvalues" dictionary
+ oAuth2RefreshHeaders = "auth:oauth2:authorization_headers" dictionary
+ oAuth2RefreshQueryParams = "auth:oauth2:authorization_queryparams" dictionary
+ oAuth2RefreshBodyValues = "auth:oauth2:authorization_bodyvalues" dictionary
+
headers = "headers" dictionary
query = "query" dictionary
@@ -348,6 +363,134 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}
};
},
+ oAuth2AuthorizationHeaders(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ authorizationHeaders: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorizationHeaders || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2AuthorizationQueryParams(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ authorizationQueryParams: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorizationQueryParams || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2TokenHeaders(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ tokenHeaders: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenHeaders || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2TokenQueryParams(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ tokenQueryParams: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenQueryParams || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2TokenBodyValues(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ tokenBodyValues: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenBodyValues || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2RefreshHeaders(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ refreshHeaders: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshHeaders || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2RefreshQueryParams(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ refreshQueryParams: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshQueryParams || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
+ oAuth2RefreshBodyValues(_1, dictionary) {
+ return {
+ auth: {
+ oauth2: {
+ ...(dictionary?.ast?.auth?.oauth2 || {}),
+ additionalParameters: {
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}),
+ refreshBodyValues: [
+ ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshBodyValues || []),
+ ...mapPairListToKeyValPairs(dictionary.ast)
+ ]
+ }
+ }
+ }
+ };
+ },
authwsse(_1, dictionary) {
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
const userKey = _.find(auth, { name: 'username' });
diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js
index 776cca7d5..d8a7b13a3 100644
--- a/packages/bruno-lang/v2/src/jsonToBru.js
+++ b/packages/bruno-lang/v2/src/jsonToBru.js
@@ -249,6 +249,35 @@ ${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).
`;
break;
}
+
+ if (auth?.oauth2?.additionalParameters) {
+ switch(auth?.oauth2?.additionalParameters) {
+ case 'authorizationHeaders' :
+ let authorizationHeaders = auth?.oauth2?.additionalParameters?.authorizationHeaders;
+ bru += `auth:oauth2:authorization_headers {
+${enabled(authorizationHeaders)
+ .map((item) => `${item.name}: ${item.value}`)
+ .join('\n')}
+}`;
+ break;
+ case 'authorizationQueryParams' :
+ let authorizationQueryParams = auth?.oauth2?.additionalParameters?.authorizationQueryParams;
+ bru += `auth:oauth2:authorization_queryparams {
+${enabled(authorizationQueryParams)
+ .map((item) => `${item.name}: ${item.value}`)
+ .join('\n')}
+}`;
+ break;
+ case 'authorizationBodyValues' :
+ let authorizationBodyValues = auth?.oauth2?.additionalParameters?.authorizationBodyValues;
+ bru += `auth:oauth2:authorization_queryparams {
+ ${enabled(authorizationBodyValues)
+ .map((item) => `${item.name}: ${item.value}`)
+ .join('\n')}
+ }`;
+ break;
+ }
+ }
}
if (auth && auth.apikey) {