diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 1b54422e34..0253878c3e 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -215,34 +215,36 @@ const configureRequest = async ( if (request.oauth2) { let requestCopy = cloneDeep(request); switch (request?.oauth2?.grantType) { - case 'authorization_code': + case 'authorization_code': { interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars); - const { data: authorizationCodeData, url: authorizationCodeAccessTokenUrl } = + const { accessTokenRequestHeaders, accessTokenRequestData, accessTokenRequestUrl } = await resolveOAuth2AuthorizationCodeAccessToken(requestCopy, collectionUid); request.method = 'POST'; - request.headers['content-type'] = 'application/x-www-form-urlencoded'; - request.data = authorizationCodeData; - request.url = authorizationCodeAccessTokenUrl; + request.headers = accessTokenRequestHeaders; + request.data = accessTokenRequestData; + request.url = accessTokenRequestUrl; break; - case 'client_credentials': + } + case 'client_credentials': { interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars); - const { data: clientCredentialsData, url: clientCredentialsAccessTokenUrl } = + const { accessTokenRequestHeaders, accessTokenRequestData, accessTokenRequestUrl } = await transformClientCredentialsRequest(requestCopy); request.method = 'POST'; - request.headers['content-type'] = 'application/x-www-form-urlencoded'; - request.data = clientCredentialsData; - request.url = clientCredentialsAccessTokenUrl; + request.headers = accessTokenRequestHeaders; + request.data = accessTokenRequestData; + request.url = accessTokenRequestUrl; break; - case 'password': + } + case 'password': { interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars); - const { data: passwordData, url: passwordAccessTokenUrl } = await transformPasswordCredentialsRequest( - requestCopy - ); + const { accessTokenRequestHeaders, accessTokenRequestData, accessTokenRequestUrl } = + await transformPasswordCredentialsRequest(requestCopy); request.method = 'POST'; - request.headers['content-type'] = 'application/x-www-form-urlencoded'; - request.data = passwordData; - request.url = passwordAccessTokenUrl; + request.headers = accessTokenRequestHeaders; + request.data = accessTokenRequestData; + request.url = accessTokenRequestUrl; break; + } } } diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index 0d95867b84..84962b08b5 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -141,28 +141,15 @@ const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEn } 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.data = { - grant_type: 'password', - username, - password, - client_id: clientId, - client_secret: clientSecret, - 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) || ''; @@ -170,24 +157,17 @@ const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEn 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.data = { - grant_type: 'client_credentials', - client_id: clientId, - client_secret: clientSecret, - 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 7a1a5b5031..1dfe9eeee5 100644 --- a/packages/bruno-electron/src/ipc/network/oauth2-helper.js +++ b/packages/bruno-electron/src/ipc/network/oauth2-helper.js @@ -3,6 +3,10 @@ const crypto = require('crypto'); const { authorizeUserInWindow } = require('./authorize-user-in-window'); const Oauth2Store = require('../../store/oauth2'); +const encodeClientCredentials = (clientId, clientSecret) => { + return 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64'); +}; + const generateCodeVerifier = () => { return crypto.randomBytes(22).toString('hex'); }; @@ -23,23 +27,33 @@ const resolveOAuth2AuthorizationCodeAccessToken = async (request, collectionUid) let requestCopy = cloneDeep(request); const { authorizationCode } = await getOAuth2AuthorizationCode(requestCopy, codeChallenge, collectionUid); const oAuth = get(requestCopy, 'oauth2', {}); - const { clientId, clientSecret, callbackUrl, scope, state, pkce } = oAuth; - const data = { + const { clientId, clientSecret, clientSecretMethod, callbackUrl, scope, state, pkce } = oAuth; + + const accessTokenRequestHeaders = request.headers; + accessTokenRequestHeaders['content-type'] = 'application/x-www-form-urlencoded'; + if (clientSecretMethod === 'client_credentials_basic') { + accessTokenRequestHeaders['Authorization'] = encodeClientCredentials(clientId, clientSecret); + } + + const accessTokenRequestData = { grant_type: 'authorization_code', code: authorizationCode, - redirect_uri: callbackUrl, - client_id: clientId, - client_secret: clientSecret, - state: state + redirect_uri: callbackUrl }; + if (pkce) { - data['code_verifier'] = codeVerifier; + accessTokenRequestData['code_verifier'] = codeVerifier; + } + if (clientSecretMethod === 'client_credentials_post') { + accessTokenRequestData['client_id'] = clientId; + accessTokenRequestData['client_secret'] = clientSecret; } - const url = requestCopy?.oauth2?.accessTokenUrl; + const accessTokenRequestUrl = requestCopy?.oauth2?.accessTokenUrl; return { - data, - url + accessTokenRequestHeaders, + accessTokenRequestData, + accessTokenRequestUrl }; }; @@ -83,19 +97,30 @@ const getOAuth2AuthorizationCode = (request, codeChallenge, collectionUid) => { const transformClientCredentialsRequest = async (request) => { let requestCopy = cloneDeep(request); const oAuth = get(requestCopy, 'oauth2', {}); - const { clientId, clientSecret, scope } = oAuth; - const data = { - grant_type: 'client_credentials', - client_id: clientId, - client_secret: clientSecret + const { clientId, clientSecret, clientSecretMethod, scope } = oAuth; + + const accessTokenRequestHeaders = request.headers; + accessTokenRequestHeaders['content-type'] = 'application/x-www-form-urlencoded'; + if (clientSecretMethod === 'client_credentials_basic') { + accessTokenRequestHeaders['Authorization'] = encodeClientCredentials(clientId, clientSecret); + } + + const accessTokenRequestData = { + grant_type: 'client_credentials' }; if (scope) { - data.scope = scope; + accessTokenRequestData.scope = scope; + } + if (clientSecretMethod === 'client_credentials_post') { + accessTokenRequestData['client_id'] = clientId; + accessTokenRequestData['client_secret'] = clientSecret; } - const url = requestCopy?.oauth2?.accessTokenUrl; + + const accessTokenRequestUrl = requestCopy?.oauth2?.accessTokenUrl; return { - data, - url + accessTokenRequestHeaders, + accessTokenRequestData, + accessTokenRequestUrl }; }; @@ -104,21 +129,32 @@ const transformClientCredentialsRequest = async (request) => { const transformPasswordCredentialsRequest = async (request) => { let requestCopy = cloneDeep(request); const oAuth = get(requestCopy, 'oauth2', {}); - const { username, password, clientId, clientSecret, scope } = oAuth; - const data = { + const { username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth; + + const accessTokenRequestHeaders = request.headers; + accessTokenRequestHeaders['content-type'] = 'application/x-www-form-urlencoded'; + if (clientSecretMethod === 'client_credentials_basic') { + accessTokenRequestHeaders['Authorization'] = encodeClientCredentials(clientId, clientSecret); + } + + const accessTokenRequestData = { grant_type: 'password', username, - password, - client_id: clientId, - client_secret: clientSecret + password }; if (scope) { - data.scope = scope; + accessTokenRequestData.scope = scope; } - const url = requestCopy?.oauth2?.accessTokenUrl; + if (clientSecretMethod === 'client_credentials_post') { + accessTokenRequestData['client_id'] = clientId; + accessTokenRequestData['client_secret'] = clientSecret; + } + + const accessTokenRequestUrl = requestCopy?.oauth2?.accessTokenUrl; return { - data, - url + accessTokenRequestHeaders, + accessTokenRequestData, + accessTokenRequestUrl }; }; diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 8a747f5d8c..ea4f6ba291 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -1,7 +1,7 @@ const os = require('os'); const { get, each, filter, extend, compact } = require('lodash'); const decomment = require('decomment'); -var JSONbig = require('json-bigint'); +const JSONbig = require('json-bigint'); const FormData = require('form-data'); const fs = require('fs'); const path = require('path'); @@ -258,6 +258,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; @@ -269,6 +270,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') @@ -280,6 +282,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;