diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/index.js index 9db8ab84fb..1e75b4fb44 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/index.js @@ -6,7 +6,8 @@ import SingleLineEditor from 'components/SingleLineEditor'; import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; -import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index'; +import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections'; +import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector'; const OAuth2AuthorizationCode = ({ collection }) => { const dispatch = useDispatch(); @@ -20,7 +21,8 @@ const OAuth2AuthorizationCode = ({ collection }) => { const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); - const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth; + const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope, state, pkce } = + oAuth; const handleChange = (key, value) => { dispatch( @@ -34,6 +36,7 @@ const OAuth2AuthorizationCode = ({ collection }) => { accessTokenUrl, clientId, clientSecret, + clientSecretMethod, scope, state, pkce, @@ -55,6 +58,7 @@ const OAuth2AuthorizationCode = ({ collection }) => { accessTokenUrl, clientId, clientSecret, + clientSecretMethod, scope, state, pkce: !Boolean(oAuth?.['pkce']) @@ -92,6 +96,7 @@ const OAuth2AuthorizationCode = ({ collection }) => { onChange={handlePKCEToggle} /> + ); }; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js index 856e9373eb..a71d5c167c 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js @@ -6,7 +6,8 @@ import SingleLineEditor from 'components/SingleLineEditor'; import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; -import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index'; +import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections'; +import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector'; const OAuth2ClientCredentials = ({ collection }) => { const dispatch = useDispatch(); @@ -20,7 +21,7 @@ const OAuth2ClientCredentials = ({ collection }) => { const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); - const { accessTokenUrl, clientId, clientSecret, scope } = oAuth; + const { accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope } = oAuth; const handleChange = (key, value) => { dispatch( @@ -32,6 +33,7 @@ const OAuth2ClientCredentials = ({ collection }) => { accessTokenUrl, clientId, clientSecret, + clientSecretMethod, scope, [key]: value } @@ -60,6 +62,7 @@ const OAuth2ClientCredentials = ({ collection }) => { ); })} + ); }; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js index 068f0070c4..912546adfc 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js @@ -7,6 +7,7 @@ import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/Redux import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections'; +import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector'; const OAuth2PasswordCredentials = ({ collection }) => { const dispatch = useDispatch(); @@ -20,7 +21,7 @@ const OAuth2PasswordCredentials = ({ collection }) => { const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); - const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth; + const { accessTokenUrl, username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth; const handleChange = (key, value) => { dispatch( @@ -34,6 +35,7 @@ const OAuth2PasswordCredentials = ({ collection }) => { password, clientId, clientSecret, + clientSecretMethod, scope, [key]: value } @@ -62,6 +64,7 @@ const OAuth2PasswordCredentials = ({ collection }) => { ); })} + ); }; 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 0265ddbe43..2069d5e5dd 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 @@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections'; import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; +import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector'; const OAuth2AuthorizationCode = ({ item, collection }) => { const dispatch = useDispatch(); @@ -20,7 +21,8 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); - const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth; + const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope, state, pkce } = + oAuth; const handleChange = (key, value) => { dispatch( @@ -35,6 +37,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { accessTokenUrl, clientId, clientSecret, + clientSecretMethod, state, scope, pkce, @@ -57,6 +60,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { accessTokenUrl, clientId, clientSecret, + clientSecretMethod, state, scope, pkce: !Boolean(oAuth?.['pkce']) @@ -96,6 +100,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => { onChange={handlePKCEToggle} /> + ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js index 1bbee2253c..c098f0462e 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js @@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections'; import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; +import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector'; const OAuth2ClientCredentials = ({ item, collection }) => { const dispatch = useDispatch(); @@ -20,7 +21,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => { const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); - const { accessTokenUrl, clientId, clientSecret, scope } = oAuth; + const { accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope } = oAuth; const handleChange = (key, value) => { dispatch( @@ -33,6 +34,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => { accessTokenUrl, clientId, clientSecret, + clientSecretMethod, scope, [key]: value } @@ -62,6 +64,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => { ); })} + ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector/StyledWrapper.js new file mode 100644 index 0000000000..2ae9cbf12e --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector/StyledWrapper.js @@ -0,0 +1,25 @@ +import styled from 'styled-components'; + +const Wrapper = styled.div` + font-size: 0.8125rem; + + .client-credentials-secret-mode-selector { + padding: 0.5rem 0px; + border-radius: 3px; + border: solid 1px ${(props) => props.theme.input.border}; + background-color: ${(props) => props.theme.input.bg}; + + .client-credentials-secret-label { + width: fit-content; + color: ${(props) => props.theme.colors.text.yellow}; + justify-content: space-between; + padding: 0 0.5rem; + } + + .dropdown-item { + padding: 0.2rem 0.6rem !important; + } + } +`; + +export default Wrapper; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector/index.js new file mode 100644 index 0000000000..a4c881155f --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector/index.js @@ -0,0 +1,82 @@ +import React, { forwardRef, useEffect, useRef } from 'react'; +import Dropdown from 'components/Dropdown'; +import StyledWrapper from './StyledWrapper'; +import { IconCaretDown } from '@tabler/icons'; +import { updateAuth, updateCollectionAuth } from 'providers/ReduxStore/slices/collections'; +import { useDispatch } from 'react-redux'; +import { humanizeOAuth2ClientSecretMethod } from 'utils/collections'; + +const ClientCredentialsMethodSelector = ({ item, collection, oAuth }) => { + const clientSecretMethods = ['client_credentials_basic', 'client_credentials_post']; + + const dispatch = useDispatch(); + const dropDownRef = useRef(); + const onDropdownCreate = (ref) => (dropDownRef.current = ref); + + const Icon = forwardRef((props, ref) => { + return ( +
+ {humanizeOAuth2ClientSecretMethod(oAuth?.clientSecretMethod)}{' '} + +
+ ); + }); + + const onClientSecretMethodChange = (clientSecretMethod) => { + if (item) { + // Update request level authentication + dispatch( + updateAuth({ + mode: 'oauth2', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + ...oAuth, + clientSecretMethod: clientSecretMethod + } + }) + ); + } else { + // Update collection level authentication + dispatch( + updateCollectionAuth({ + mode: 'oauth2', + collectionUid: collection.uid, + content: { + ...oAuth, + clientSecretMethod: clientSecretMethod + } + }) + ); + } + }; + + useEffect(() => { + !oAuth?.clientSecretMethod && onClientSecretMethodChange(clientSecretMethods[0]); + }, [oAuth.clientSecretMethod]); + + return ( + + +
+ } placement="bottom-end"> + {clientSecretMethods.map((item, index) => ( +
{ + dropDownRef.current.hide(); + onClientSecretMethodChange(item); + }} + > + {' '} + {humanizeOAuth2ClientSecretMethod(item)} + {index === 0 ? ` (Default)` : ``} +
+ ))} +
+
+
+ ); +}; +export default ClientCredentialsMethodSelector; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js index 6911c6457d..962e4d6675 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; @@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections'; import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; +import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector'; const OAuth2PasswordCredentials = ({ item, collection }) => { const dispatch = useDispatch(); @@ -20,7 +21,7 @@ const OAuth2PasswordCredentials = ({ item, collection }) => { const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); - const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth; + const { accessTokenUrl, username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth; const handleChange = (key, value) => { dispatch( @@ -35,6 +36,7 @@ const OAuth2PasswordCredentials = ({ item, collection }) => { password, clientId, clientSecret, + clientSecretMethod, scope, [key]: value } @@ -64,6 +66,7 @@ const OAuth2PasswordCredentials = ({ item, collection }) => { ); })} + ); }; diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index d770c60a3c..b09f5aa09d 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -181,7 +181,7 @@ export const moveCollectionItemToRootOfCollection = (collection, draggedItem) => draggedItemParent.items = filter(draggedItemParent.items, (i) => i.uid !== draggedItem.uid); collection.items = sortBy(collection.items, (item) => item.seq); collection.items.push(draggedItem); - if (draggedItem.type == 'folder') { + if (draggedItem.type === 'folder') { draggedItem.pathname = path.join(collection.pathname, draggedItem.name); } else { draggedItem.pathname = path.join(collection.pathname, draggedItem.filename); @@ -733,6 +733,22 @@ export const humanizeGrantType = (mode) => { return label; }; +export const humanizeOAuth2ClientSecretMethod = (mode) => { + let label = 'N/A'; + switch (mode) { + case 'client_credentials_basic': { + label = 'As Basic Auth Header'; + break; + } + case 'client_credentials_post': { + label = 'In Request Body'; + break; + } + } + + return label; +}; + export const refreshUidsInItem = (item) => { item.uid = uuid(); diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index 9478abf495..827f1b69b6 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -156,20 +156,15 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc } if (request?.oauth2?.grantType) { - let username, password, scope, clientId, clientSecret; switch (request.oauth2.grantType) { case 'password': - username = _interpolate(request.oauth2.username) || ''; - password = _interpolate(request.oauth2.password) || ''; - clientId = _interpolate(request.oauth2.clientId) || ''; - clientSecret = _interpolate(request.oauth2.clientSecret) || ''; - scope = _interpolate(request.oauth2.scope) || ''; request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; - request.oauth2.username = username; - request.oauth2.password = password; - request.oauth2.clientId = clientId; - request.oauth2.clientSecret = clientSecret; - request.oauth2.scope = scope; + request.oauth2.username = _interpolate(request.oauth2.username) || ''; + request.oauth2.password = _interpolate(request.oauth2.password) || ''; + request.oauth2.clientId = _interpolate(request.oauth2.clientId) || ''; + request.oauth2.clientSecret = _interpolate(request.oauth2.clientSecret) || ''; + request.oauth2.clientSecretMethod = _interpolate(request.oauth2.clientSecretMethod) || ''; + request.oauth2.scope = _interpolate(request.oauth2.scope) || ''; break; case 'authorization_code': request.oauth2.callbackUrl = _interpolate(request.oauth2.callbackUrl) || ''; @@ -177,18 +172,17 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; request.oauth2.clientId = _interpolate(request.oauth2.clientId) || ''; request.oauth2.clientSecret = _interpolate(request.oauth2.clientSecret) || ''; + request.oauth2.clientSecretMethod = _interpolate(request.oauth2.clientSecretMethod) || ''; request.oauth2.scope = _interpolate(request.oauth2.scope) || ''; request.oauth2.state = _interpolate(request.oauth2.state) || ''; request.oauth2.pkce = _interpolate(request.oauth2.pkce) || false; break; case 'client_credentials': - clientId = _interpolate(request.oauth2.clientId) || ''; - clientSecret = _interpolate(request.oauth2.clientSecret) || ''; - scope = _interpolate(request.oauth2.scope) || ''; request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; - request.oauth2.clientId = clientId; - request.oauth2.clientSecret = clientSecret; - request.oauth2.scope = scope; + request.oauth2.clientId = _interpolate(request.oauth2.clientId) || ''; + request.oauth2.clientSecret = _interpolate(request.oauth2.clientSecret) || ''; + request.oauth2.clientSecretMethod = _interpolate(request.oauth2.clientSecretMethod) || ''; + request.oauth2.scope = _interpolate(request.oauth2.scope) || ''; break; default: break; diff --git a/packages/bruno-electron/src/ipc/network/oauth2-helper.js b/packages/bruno-electron/src/ipc/network/oauth2-helper.js index cdff9627d5..d27ed785eb 100644 --- a/packages/bruno-electron/src/ipc/network/oauth2-helper.js +++ b/packages/bruno-electron/src/ipc/network/oauth2-helper.js @@ -6,6 +6,22 @@ const { makeAxiosInstance } = require('./axios-instance'); const oauth2Store = new Oauth2Store(); +const setClientCredentials = (clientId, clientSecret, clientSecretMethod, request) => { + if (clientSecret) { + switch (clientSecretMethod) { + case 'client_credentials_post': { + request.data["client_id"] = clientId; + request.data["client_secret"] = clientSecret; + break; + } + case 'client_credentials_basic': { + request.headers["Authorization"] = 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64'); + break; + } + } + } +}; + const generateCodeVerifier = () => { return crypto.randomBytes(22).toString('hex'); }; @@ -44,13 +60,12 @@ const oauth2AuthorizeWithAuthorizationCode = async (request, collectionUid) => { let requestCopy = cloneDeep(request); const { authorizationCode } = await getOAuth2AuthorizationCode(requestCopy, codeChallenge, collectionUid); const oAuth = get(requestCopy, 'oauth2', {}); - const { clientId, clientSecret, callbackUrl, pkce } = oAuth; + const { clientId, clientSecret, clientSecretMethod, callbackUrl, pkce } = oAuth; + const data = { grant_type: 'authorization_code', code: authorizationCode, - redirect_uri: callbackUrl, - client_id: clientId, - client_secret: clientSecret + redirect_uri: callbackUrl }; if (pkce) { data['code_verifier'] = codeVerifier; @@ -61,6 +76,8 @@ const oauth2AuthorizeWithAuthorizationCode = async (request, collectionUid) => { request.data = data; request.url = request?.oauth2?.accessTokenUrl; + setClientCredentials(clientId, clientSecret, clientSecretMethod, request); + const axiosInstance = makeAxiosInstance(); const response = await axiosInstance(request); const credentials = JSON.parse(response.data); @@ -113,11 +130,9 @@ const oauth2AuthorizeWithClientCredentials = async (request, collectionUid) => { let requestCopy = cloneDeep(request); const oAuth = get(requestCopy, 'oauth2', {}); - const { clientId, clientSecret, scope } = oAuth; + const { clientId, clientSecret, clientSecretMethod, scope } = oAuth; const data = { - grant_type: 'client_credentials', - client_id: clientId, - client_secret: clientSecret + grant_type: 'client_credentials' }; if (scope) { data.scope = scope; @@ -128,6 +143,8 @@ const oauth2AuthorizeWithClientCredentials = async (request, collectionUid) => { request.data = data; request.url = request?.oauth2?.accessTokenUrl; + setClientCredentials(clientId, clientSecret, clientSecretMethod, request); + const axiosInstance = makeAxiosInstance(); let response = await axiosInstance(request); let credentials = JSON.parse(response.data); @@ -145,13 +162,11 @@ const oauth2AuthorizeWithPasswordCredentials = async (request, collectionUid) => } const oAuth = get(request, 'oauth2', {}); - const { username, password, clientId, clientSecret, scope } = oAuth; + const { username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth; const data = { grant_type: 'password', username, - password, - client_id: clientId, - client_secret: clientSecret + password }; if (scope) { data.scope = scope; @@ -162,6 +177,8 @@ const oauth2AuthorizeWithPasswordCredentials = async (request, collectionUid) => request.data = data; request.url = request?.oauth2?.accessTokenUrl; + setClientCredentials(clientId, clientSecret, clientSecretMethod, request); + const axiosInstance = makeAxiosInstance(); let response = await axiosInstance(request); let credentials = JSON.parse(response.data); diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 6b27d32d30..5df02098fb 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -103,6 +103,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { password: get(request, 'auth.oauth2.password'), clientId: get(request, 'auth.oauth2.clientId'), clientSecret: get(request, 'auth.oauth2.clientSecret'), + clientSecretMethod: get(request, 'auth.oauth2.clientSecretMethod'), scope: get(request, 'auth.oauth2.scope') }; break; @@ -114,6 +115,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { accessTokenUrl: get(request, 'auth.oauth2.accessTokenUrl'), clientId: get(request, 'auth.oauth2.clientId'), clientSecret: get(request, 'auth.oauth2.clientSecret'), + clientSecretMethod: get(request, 'auth.oauth2.clientSecretMethod'), scope: get(request, 'auth.oauth2.scope'), state: get(request, 'auth.oauth2.state'), pkce: get(request, 'auth.oauth2.pkce') @@ -125,6 +127,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { accessTokenUrl: get(request, 'auth.oauth2.accessTokenUrl'), clientId: get(request, 'auth.oauth2.clientId'), clientSecret: get(request, 'auth.oauth2.clientSecret'), + clientSecretMethod: get(request, 'auth.oauth2.clientSecretMethod'), scope: get(request, 'auth.oauth2.scope') }; break; diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 228691c1b2..1651d4544b 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -460,6 +460,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { const accessTokenUrlKey = _.find(auth, { name: 'access_token_url' }); const clientIdKey = _.find(auth, { name: 'client_id' }); const clientSecretKey = _.find(auth, { name: 'client_secret' }); + const clientSecretMethodKey = _.find(auth, { name: 'client_secret_method' }); const scopeKey = _.find(auth, { name: 'scope' }); const stateKey = _.find(auth, { name: 'state' }); const pkceKey = _.find(auth, { name: 'pkce' }); @@ -474,6 +475,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { password: passwordKey ? passwordKey.value : '', clientId: clientIdKey ? clientIdKey.value : '', clientSecret: clientSecretKey ? clientSecretKey.value : '', + clientSecretMethod: clientSecretMethodKey ? clientSecretMethodKey.value : '', scope: scopeKey ? scopeKey.value : '' } : grantTypeKey?.value && grantTypeKey?.value == 'authorization_code' @@ -484,6 +486,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '', clientId: clientIdKey ? clientIdKey.value : '', clientSecret: clientSecretKey ? clientSecretKey.value : '', + clientSecretMethod: clientSecretMethodKey ? clientSecretMethodKey.value : '', scope: scopeKey ? scopeKey.value : '', state: stateKey ? stateKey.value : '', pkce: pkceKey ? JSON.parse(pkceKey?.value || false) : false @@ -494,6 +497,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '', clientId: clientIdKey ? clientIdKey.value : '', clientSecret: clientSecretKey ? clientSecretKey.value : '', + clientSecretMethod: clientSecretMethodKey ? clientSecretMethodKey.value : '', scope: scopeKey ? scopeKey.value : '' } : {} diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index 5180f0193d..2591890739 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -255,6 +255,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { const accessTokenUrlKey = _.find(auth, { name: 'access_token_url' }); const clientIdKey = _.find(auth, { name: 'client_id' }); const clientSecretKey = _.find(auth, { name: 'client_secret' }); + const clientSecretMethodKey = _.find(auth, { name: 'client_secret_method' }); const scopeKey = _.find(auth, { name: 'scope' }); const stateKey = _.find(auth, { name: 'state' }); const pkceKey = _.find(auth, { name: 'pkce' }); @@ -269,6 +270,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { password: passwordKey ? passwordKey.value : '', clientId: clientIdKey ? clientIdKey.value : '', clientSecret: clientSecretKey ? clientSecretKey.value : '', + clientSecretMethod: clientSecretMethodKey ? clientSecretMethodKey.value : '', scope: scopeKey ? scopeKey.value : '' } : grantTypeKey?.value && grantTypeKey?.value == 'authorization_code' @@ -279,6 +281,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '', clientId: clientIdKey ? clientIdKey.value : '', clientSecret: clientSecretKey ? clientSecretKey.value : '', + clientSecretMethod: clientSecretMethodKey ? clientSecretMethodKey.value : '', scope: scopeKey ? scopeKey.value : '', state: stateKey ? stateKey.value : '', pkce: pkceKey ? JSON.parse(pkceKey?.value || false) : false @@ -289,6 +292,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '', clientId: clientIdKey ? clientIdKey.value : '', clientSecret: clientSecretKey ? clientSecretKey.value : '', + clientSecretMethod: clientSecretMethodKey ? clientSecretMethodKey.value : '', scope: scopeKey ? scopeKey.value : '' } : {} diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index 5c8a573b62..8bca9abfcc 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -175,6 +175,7 @@ ${indentString(`username: ${auth?.oauth2?.username || ''}`)} ${indentString(`password: ${auth?.oauth2?.password || ''}`)} ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} +${indentString(`client_secret_method: ${auth?.oauth2?.clientSecretMethod || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} } @@ -188,6 +189,7 @@ ${indentString(`authorization_url: ${auth?.oauth2?.authorizationUrl || ''}`)} ${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)} ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} +${indentString(`client_secret_method: ${auth?.oauth2?.clientSecretMethod || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`state: ${auth?.oauth2?.state || ''}`)} ${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)} @@ -201,6 +203,7 @@ ${indentString(`grant_type: client_credentials`)} ${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)} ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} +${indentString(`client_secret_method: ${auth?.oauth2?.clientSecretMethod || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} } diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js index 8b162b7a6f..5721d0345a 100644 --- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -142,6 +142,7 @@ ${indentString(`username: ${auth?.oauth2?.username || ''}`)} ${indentString(`password: ${auth?.oauth2?.password || ''}`)} ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} +${indentString(`client_secret_method: ${auth?.oauth2?.clientSecretMethod || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} } @@ -155,6 +156,7 @@ ${indentString(`authorization_url: ${auth?.oauth2?.authorizationUrl || ''}`)} ${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)} ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} +${indentString(`client_secret_method: ${auth?.oauth2?.clientSecretMethod || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`state: ${auth?.oauth2?.state || ''}`)} ${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)} @@ -168,6 +170,7 @@ ${indentString(`grant_type: client_credentials`)} ${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)} ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} +${indentString(`client_secret_method: ${auth?.oauth2?.clientSecretMethod || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} } diff --git a/packages/bruno-lang/v2/tests/fixtures/collection.bru b/packages/bruno-lang/v2/tests/fixtures/collection.bru index f11954ebf1..24eef68825 100644 --- a/packages/bruno-lang/v2/tests/fixtures/collection.bru +++ b/packages/bruno-lang/v2/tests/fixtures/collection.bru @@ -31,6 +31,19 @@ auth:digest { password: secret } +auth:oauth2 { + grant_type: authorization_code + callback_url: http://localhost:8080/api/auth/oauth2/authorization_code/callback + authorization_url: http://localhost:8080/api/auth/oauth2/authorization_code/authorize + access_token_url: http://localhost:8080/api/auth/oauth2/authorization_code/token + client_id: client_id_1 + client_secret: client_secret_1 + client_secret_method: client_credentials_post + scope: read write + state: 807061d5f0be + pkce: false +} + vars:pre-request { departingDate: 2020-01-01 ~returningDate: 2020-01-02 diff --git a/packages/bruno-lang/v2/tests/fixtures/collection.json b/packages/bruno-lang/v2/tests/fixtures/collection.json index 102ee295cb..2a0572159f 100644 --- a/packages/bruno-lang/v2/tests/fixtures/collection.json +++ b/packages/bruno-lang/v2/tests/fixtures/collection.json @@ -35,6 +35,18 @@ "wsse": { "username": "john", "password": "secret" + }, + "oauth2": { + "grantType": "authorization_code", + "clientId": "client_id_1", + "clientSecret": "client_secret_1", + "clientSecretMethod": "client_credentials_post", + "authorizationUrl": "http://localhost:8080/api/auth/oauth2/authorization_code/authorize", + "callbackUrl": "http://localhost:8080/api/auth/oauth2/authorization_code/callback", + "accessTokenUrl": "http://localhost:8080/api/auth/oauth2/authorization_code/token", + "scope": "read write", + "state": "807061d5f0be", + "pkce": false } }, "vars": { diff --git a/packages/bruno-lang/v2/tests/fixtures/request.bru b/packages/bruno-lang/v2/tests/fixtures/request.bru index 1a3efeab72..a9c6dffcb7 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.bru +++ b/packages/bruno-lang/v2/tests/fixtures/request.bru @@ -61,6 +61,7 @@ auth:oauth2 { access_token_url: http://localhost:8080/api/auth/oauth2/authorization_code/token client_id: client_id_1 client_secret: client_secret_1 + client_secret_method: client_credentials_basic scope: read write state: 807061d5f0be pkce: false diff --git a/packages/bruno-lang/v2/tests/fixtures/request.json b/packages/bruno-lang/v2/tests/fixtures/request.json index 9c8ed143da..6f195d0877 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.json +++ b/packages/bruno-lang/v2/tests/fixtures/request.json @@ -77,6 +77,7 @@ "grantType": "authorization_code", "clientId": "client_id_1", "clientSecret": "client_secret_1", + "clientSecretMethod": "client_credentials_basic", "authorizationUrl": "http://localhost:8080/api/auth/oauth2/authorization_code/authorize", "callbackUrl": "http://localhost:8080/api/auth/oauth2/authorization_code/callback", "accessTokenUrl": "http://localhost:8080/api/auth/oauth2/authorization_code/token", diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 3d5959f15d..76a42faa18 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -188,7 +188,14 @@ const oauth2Schema = Yup.object({ is: (val) => ['authorization_code'].includes(val), then: Yup.boolean().default(false), otherwise: Yup.boolean() - }) + }), + clientSecretMethod: Yup.string() + .oneOf(['client_credentials_basic', 'client_credentials_post']) + .when('clientSecret', { + is: (clientSecret) => clientSecret != null, + then: Yup.string().default('client_credentials_basic'), + otherwise: Yup.string().nullable().strip() + }) }) .noUnknown(true) .strict();