props.theme.input.border};
+ background-color: ${(props) => props.theme.input.bg};
+ }
+`;
+
+export default Wrapper;
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
new file mode 100644
index 000000000..be56ba1e1
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js
@@ -0,0 +1,70 @@
+import React from 'react';
+import get from 'lodash/get';
+import { useTheme } from 'providers/Theme';
+import { useDispatch } from 'react-redux';
+import SingleLineEditor from 'components/SingleLineEditor';
+import { updateAuth } from 'providers/ReduxStore/slices/collections';
+import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
+import StyledWrapper from './StyledWrapper';
+import { inputsConfig } from './inputsConfig';
+
+const OAuth2AuthorizationCode = ({ item, collection }) => {
+ const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
+
+ const oAuth = item.draft ? get(item, 'draft.request.auth.oauth2', {}) : get(item, 'request.auth.oauth2', {});
+
+ const handleRun = async () => {
+ dispatch(sendRequest(item, collection.uid));
+ };
+
+ const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
+
+ const { accessTokenUrl, username, password, scope } = oAuth;
+
+ const handleChange = (key, value) => {
+ dispatch(
+ updateAuth({
+ mode: 'oauth2',
+ collectionUid: collection.uid,
+ itemUid: item.uid,
+ content: {
+ grantType: 'password',
+ accessTokenUrl,
+ username,
+ password,
+ scope,
+ [key]: value
+ }
+ })
+ );
+ };
+
+ return (
+
+ {inputsConfig.map((input) => {
+ const { key, label } = input;
+ return (
+
+
+
+ handleChange(key, val)}
+ onRun={handleRun}
+ collection={collection}
+ />
+
+
+ );
+ })}
+
+
+ );
+};
+
+export default OAuth2AuthorizationCode;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/inputsConfig.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/inputsConfig.js
new file mode 100644
index 000000000..1a20fed83
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/inputsConfig.js
@@ -0,0 +1,20 @@
+const inputsConfig = [
+ {
+ key: 'accessTokenUrl',
+ label: 'Access Token URL'
+ },
+ {
+ key: 'username',
+ label: 'Username'
+ },
+ {
+ key: 'password',
+ label: 'Password'
+ },
+ {
+ key: 'scope',
+ label: 'Scope'
+ }
+];
+
+export { inputsConfig };
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Ropc/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Ropc/index.js
deleted file mode 100644
index 104ebdd77..000000000
--- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Ropc/index.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react';
-import get from 'lodash/get';
-import { useTheme } from 'providers/Theme';
-import { useDispatch } from 'react-redux';
-import SingleLineEditor from 'components/SingleLineEditor';
-import { updateAuth } from 'providers/ReduxStore/slices/collections';
-import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
-import StyledWrapper from './StyledWrapper';
-
-const OAuth2Ropc = ({ item, collection }) => {
- const dispatch = useDispatch();
- const { storedTheme } = useTheme();
-
- const oAuth = item.draft ? get(item, 'draft.request.auth.oauth2', {}) : get(item, 'request.auth.oauth2', {});
-
- const handleRun = () => dispatch(sendRequest(item, collection.uid));
- const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
-
- const handleUsernameChange = (username) => {
- dispatch(
- updateAuth({
- mode: 'oauth2',
- collectionUid: collection.uid,
- itemUid: item.uid,
- content: {
- grantType: 'password',
- username: username,
- password: oAuth.password
- }
- })
- );
- };
-
- const handlePasswordChange = (password) => {
- dispatch(
- updateAuth({
- mode: 'oauth2',
- collectionUid: collection.uid,
- itemUid: item.uid,
- content: {
- grantType: 'password',
- username: oAuth.username,
- password: password
- }
- })
- );
- };
-
- return (
-
-
-
- handleUsernameChange(val)}
- onRun={handleRun}
- collection={collection}
- />
-
-
-
-
- handlePasswordChange(val)}
- onRun={handleRun}
- collection={collection}
- />
-
-
- );
-};
-
-export default OAuth2Ropc;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js
index 1d51962a5..3965c8d3e 100644
--- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js
@@ -2,14 +2,14 @@ import React from 'react';
import get from 'lodash/get';
import StyledWrapper from './StyledWrapper';
import GrantTypeSelector from './GrantTypeSelector/index';
-import OAuth2Ropc from './Ropc/index';
+import OAuth2PasswordCredentials from './PasswordCredentials/index';
import OAuth2AuthorizationCode from './AuthorizationCode/index';
import OAuth2ClientCredentials from './ClientCredentials/index';
const grantTypeComponentMap = (grantType, item, collection) => {
switch (grantType) {
case 'password':
- return
;
+ return
;
break;
case 'authorization_code':
return
;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js
index c959d5faf..f525b065c 100644
--- a/packages/bruno-app/src/components/RequestPane/Auth/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js
@@ -35,8 +35,20 @@ const Auth = ({ item, collection }) => {
case 'inherit': {
return (
-
Auth inherited from the Collection:
-
{humanizeRequestAuthMode(collectionAuth?.mode)}
+ {collectionAuth?.mode === 'oauth2' ? (
+
+
+
Collection level auth is:
+
{humanizeRequestAuthMode(collectionAuth?.mode)}
+
+
Cannot inherit Oauth2 from collection.
+
+ ) : (
+ <>
+
Auth inherited from the Collection:
+
{humanizeRequestAuthMode(collectionAuth?.mode)}
+ >
+ )}
);
}
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
index f08335826..8143cbc04 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
@@ -40,6 +40,7 @@ import { each } from 'lodash';
import { closeAllCollectionTabs } from 'providers/ReduxStore/slices/tabs';
import { resolveRequestFilename } from 'utils/common/platform';
import { parseQueryParams, splitOnFirst } from 'utils/url/index';
+import { sendCollectionOauth2Request as _sendCollectionOauth2Request } from 'utils/network/index';
export const renameCollection = (newName, collectionUid) => (dispatch, getState) => {
const state = getState();
@@ -138,6 +139,35 @@ export const saveCollectionRoot = (collectionUid) => (dispatch, getState) => {
});
};
+export const sendCollectionOauth2Request = (collectionUid) => (dispatch, getState) => {
+ const state = getState();
+ const collection = findCollectionByUid(state.collections.collections, collectionUid);
+
+ return new Promise((resolve, reject) => {
+ if (!collection) {
+ return reject(new Error('Collection not found'));
+ }
+
+ const collectionCopy = cloneDeep(collection);
+
+ const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid);
+
+ _sendCollectionOauth2Request(collection, environment, collectionCopy.collectionVariables)
+ .then((response) => {
+ if (response?.data?.error) {
+ toast.error(response?.data?.error);
+ } else {
+ toast.success('Request made successfully');
+ }
+ return response;
+ })
+ .then(resolve)
+ .catch((err) => {
+ toast.error(err.message);
+ });
+ });
+};
+
export const sendRequest = (item, collectionUid) => (dispatch, getState) => {
const state = getState();
const collection = findCollectionByUid(state.collections.collections, collectionUid);
@@ -147,7 +177,7 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => {
return reject(new Error('Collection not found'));
}
- const itemCopy = cloneDeep(item);
+ const itemCopy = cloneDeep(item || {});
const collectionCopy = cloneDeep(collection);
const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid);
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
index 41b284149..7494c6ae7 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -678,6 +678,7 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
+ item.draft.request.auth = {};
item.draft.request.auth.mode = action.payload.mode;
}
}
@@ -978,6 +979,7 @@ export const collectionsSlice = createSlice({
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
if (collection) {
+ set(collection, 'root.request.auth', {});
set(collection, 'root.request.auth.mode', action.payload.mode);
}
},
@@ -985,6 +987,8 @@ export const collectionsSlice = createSlice({
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
if (collection) {
+ set(collection, 'root.request.auth', {});
+ set(collection, 'root.request.auth.mode', action.payload.mode);
switch (action.payload.mode) {
case 'awsv4':
set(collection, 'root.request.auth.awsv4', action.payload.content);
@@ -998,6 +1002,9 @@ export const collectionsSlice = createSlice({
case 'digest':
set(collection, 'root.request.auth.digest', action.payload.content);
break;
+ case 'oauth2':
+ set(collection, 'root.request.auth.oauth2', action.payload.content);
+ break;
}
}
},
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index a77a789d4..a5b109e15 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -522,7 +522,7 @@ export const humanizeGrantType = (mode) => {
let label = 'No Auth';
switch (mode) {
case 'password': {
- label = 'Resource Owner Password Credentials';
+ label = 'Password Credentials';
break;
}
case 'authorization_code': {
diff --git a/packages/bruno-app/src/utils/network/index.js b/packages/bruno-app/src/utils/network/index.js
index 4ee055fda..2c2951592 100644
--- a/packages/bruno-app/src/utils/network/index.js
+++ b/packages/bruno-app/src/utils/network/index.js
@@ -33,6 +33,16 @@ const sendHttpRequest = async (item, collection, environment, collectionVariable
});
};
+export const sendCollectionOauth2Request = async (collection, environment, collectionVariables) => {
+ return new Promise((resolve, reject) => {
+ const { ipcRenderer } = window;
+ ipcRenderer
+ .invoke('send-collection-oauth2-request', collection, environment, collectionVariables)
+ .then(resolve)
+ .catch(reject);
+ });
+};
+
export const fetchGqlSchema = async (endpoint, environment, request, collection) => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
diff --git a/packages/bruno-cli/src/runner/interpolate-vars.js b/packages/bruno-cli/src/runner/interpolate-vars.js
index 2585c1e3c..f3466fa20 100644
--- a/packages/bruno-cli/src/runner/interpolate-vars.js
+++ b/packages/bruno-cli/src/runner/interpolate-vars.js
@@ -105,7 +105,7 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
const password = _interpolate(request.auth.password) || '';
// use auth header based approach and delete the request.auth object
- request.headers['authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
+ request.headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
delete request.auth;
}
diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js
index b6c9e74e0..78c5f7538 100644
--- a/packages/bruno-cli/src/runner/prepare-request.js
+++ b/packages/bruno-cli/src/runner/prepare-request.js
@@ -52,7 +52,7 @@ const prepareRequest = (request, collectionRoot) => {
}
if (collectionAuth.mode === 'bearer') {
- axiosRequest.headers['authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
+ axiosRequest.headers['Authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
}
}
@@ -76,7 +76,7 @@ const prepareRequest = (request, collectionRoot) => {
}
if (request.auth.mode === 'bearer') {
- axiosRequest.headers['authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
+ axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
}
}
diff --git a/packages/bruno-electron/src/ipc/network/authorize-user-in-window.js b/packages/bruno-electron/src/ipc/network/authorize-user-in-window.js
index e4439f612..57cccd29c 100644
--- a/packages/bruno-electron/src/ipc/network/authorize-user-in-window.js
+++ b/packages/bruno-electron/src/ipc/network/authorize-user-in-window.js
@@ -30,7 +30,7 @@ const authorizeUserInWindow = ({ authorizeUrl, callbackUrl }) => {
const callbackUrlWithCode = new URL(finalUrl);
const authorizationCode = callbackUrlWithCode.searchParams.get('code');
- return resolve(authorizationCode);
+ return resolve({ authorizationCode });
} catch (error) {
return reject(error);
}
diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index 3446d5256..6260d1dc7 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -12,6 +12,7 @@ const { ipcMain } = require('electron');
const { isUndefined, isNull, each, get, compact, cloneDeep } = require('lodash');
const { VarsRuntime, AssertRuntime, ScriptRuntime, TestRuntime } = require('@usebruno/js');
const prepareRequest = require('./prepare-request');
+const prepareCollectionRequest = require('./prepare-collection-request');
const prepareGqlIntrospectionRequest = require('./prepare-gql-introspection-request');
const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token');
const { uuid } = require('../../utils/common');
@@ -29,7 +30,11 @@ const { addDigestInterceptor } = require('./digestauth-helper');
const { shouldUseProxy, PatchedHttpsProxyAgent } = require('../../utils/proxy-util');
const { chooseFileToSave, writeBinaryFile } = require('../../utils/filesystem');
const { getCookieStringForUrl, addCookieToJar, getDomainsWithCookies } = require('../../utils/cookies');
-const { resolveOAuth2AuthorizationCodecessToken } = require('./oauth2-authorization-code-helper');
+const {
+ resolveOAuth2AuthorizationCodeAccessToken,
+ transformClientCredentialsRequest,
+ transformPasswordCredentialsRequest
+} = require('./oauth2-helper');
// override the default escape function to prevent escaping
Mustache.escape = function (value) {
@@ -191,12 +196,30 @@ const configureRequest = async (
const axiosInstance = makeAxiosInstance();
if (request.oauth2) {
- if (request?.oauth2?.grantType == 'authorization_code') {
- let requestCopy = cloneDeep(request);
- interpolateVars(requestCopy, envVars, collectionVariables, processEnvVars);
- const { data, url } = await resolveOAuth2AuthorizationCodecessToken(requestCopy);
- request.data = data;
- request.url = url;
+ let requestCopy = cloneDeep(request);
+ switch (request?.oauth2?.grantType) {
+ case 'authorization_code':
+ interpolateVars(requestCopy, envVars, collectionVariables, processEnvVars);
+ const { data: authorizationCodeData, url: authorizationCodeAccessTokenUrl } =
+ await resolveOAuth2AuthorizationCodeAccessToken(requestCopy);
+ request.data = authorizationCodeData;
+ request.url = authorizationCodeAccessTokenUrl;
+ break;
+ case 'client_credentials':
+ interpolateVars(requestCopy, envVars, collectionVariables, processEnvVars);
+ const { data: clientCredentialsData, url: clientCredentialsAccessTokenUrl } =
+ await transformClientCredentialsRequest(requestCopy);
+ request.data = clientCredentialsData;
+ request.url = clientCredentialsAccessTokenUrl;
+ break;
+ case 'password':
+ interpolateVars(requestCopy, envVars, collectionVariables, processEnvVars);
+ const { data: passwordData, url: passwordAccessTokenUrl } = await transformPasswordCredentialsRequest(
+ requestCopy
+ );
+ request.data = passwordData;
+ request.url = passwordAccessTokenUrl;
+ break;
}
}
@@ -219,7 +242,6 @@ const configureRequest = async (
request.headers['cookie'] = cookieString;
}
}
-
return axiosInstance;
};
@@ -594,6 +616,79 @@ const registerNetworkIpc = (mainWindow) => {
}
});
+ ipcMain.handle('send-collection-oauth2-request', async (event, collection, environment, collectionVariables) => {
+ try {
+ const collectionUid = collection.uid;
+ const collectionPath = collection.pathname;
+ const requestUid = uuid();
+
+ const collectionRoot = get(collection, 'root', {});
+ const _request = collectionRoot?.request;
+ const request = prepareCollectionRequest(_request, collectionRoot, collectionPath);
+ const envVars = getEnvVars(environment);
+ const processEnvVars = getProcessEnvVars(collectionUid);
+ const brunoConfig = getBrunoConfig(collectionUid);
+ const scriptingConfig = get(brunoConfig, 'scripts', {});
+
+ await runPreRequest(
+ request,
+ requestUid,
+ envVars,
+ collectionPath,
+ collectionRoot,
+ collectionUid,
+ collectionVariables,
+ processEnvVars,
+ scriptingConfig
+ );
+
+ interpolateVars(request, envVars, collection.collectionVariables, processEnvVars);
+ const axiosInstance = await configureRequest(
+ collection.uid,
+ request,
+ envVars,
+ collection.collectionVariables,
+ processEnvVars,
+ collectionPath
+ );
+
+ try {
+ response = await axiosInstance(request);
+ } catch (error) {
+ if (error?.response) {
+ response = error.response;
+ } else {
+ return Promise.reject(error);
+ }
+ }
+
+ const { data } = parseDataFromResponse(response);
+ response.data = data;
+
+ await runPostResponse(
+ request,
+ response,
+ requestUid,
+ envVars,
+ collectionPath,
+ collectionRoot,
+ collectionUid,
+ collectionVariables,
+ processEnvVars,
+ scriptingConfig
+ );
+
+ return {
+ status: response.status,
+ statusText: response.statusText,
+ headers: response.headers,
+ data: response.data
+ };
+ } catch (error) {
+ return Promise.reject(error);
+ }
+ });
+
ipcMain.handle('cancel-http-request', async (event, cancelTokenUid) => {
return new Promise((resolve, reject) => {
if (cancelTokenUid && cancelTokens[cancelTokenUid]) {
diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
index abf06bd86..4fd0dfe2b 100644
--- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js
+++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
@@ -104,21 +104,26 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
const username = _interpolate(request.auth.username) || '';
const password = _interpolate(request.auth.password) || '';
// use auth header based approach and delete the request.auth object
- request.headers['authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
+ request.headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
delete request.auth;
}
if (request?.oauth2?.grantType) {
+ let username, password, scope, clientId, clientSecret;
switch (request.oauth2.grantType) {
case 'password':
- let username = _interpolate(request.oauth2.username) || '';
- let password = _interpolate(request.oauth2.password) || '';
+ username = _interpolate(request.oauth2.username) || '';
+ password = _interpolate(request.oauth2.password) || '';
+ scope = _interpolate(request.oauth2.scope) || '';
+ request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || '';
request.oauth2.username = username;
request.oauth2.password = password;
+ request.oauth2.scope = scope;
request.data = {
grant_type: 'password',
username,
- password
+ password,
+ scope
};
break;
case 'authorization_code':
@@ -128,16 +133,21 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
request.oauth2.clientId = _interpolate(request.oauth2.clientId) || '';
request.oauth2.clientSecret = _interpolate(request.oauth2.clientSecret) || '';
request.oauth2.scope = _interpolate(request.oauth2.scope) || '';
+ request.oauth2.pkce = _interpolate(request.oauth2.pkce) || false;
break;
case 'client_credentials':
- let clientId = _interpolate(request.oauth2.clientId) || '';
- let clientSecret = _interpolate(request.oauth2.clientSecret) || '';
+ 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
+ client_secret: clientSecret,
+ scope
};
break;
default:
diff --git a/packages/bruno-electron/src/ipc/network/oauth2-authorization-code-helper.js b/packages/bruno-electron/src/ipc/network/oauth2-authorization-code-helper.js
deleted file mode 100644
index 303af8170..000000000
--- a/packages/bruno-electron/src/ipc/network/oauth2-authorization-code-helper.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const { get, cloneDeep } = require('lodash');
-const { authorizeUserInWindow } = require('./authorize-user-in-window');
-
-const resolveOAuth2AuthorizationCodecessToken = async (request) => {
- let requestCopy = cloneDeep(request);
- const authorization_code = await getOAuth2AuthorizationCode(requestCopy);
- const oAuth = get(requestCopy, 'oauth2', {});
- const { clientId, clientSecret, callbackUrl, scope } = oAuth;
- const data = {
- grant_type: 'authorization_code',
- code: authorization_code,
- redirect_uri: callbackUrl,
- client_id: clientId,
- client_secret: clientSecret,
- scope: scope
- };
- const url = requestCopy?.oauth2?.accessTokenUrl;
- return {
- data,
- url
- };
-};
-
-const getOAuth2AuthorizationCode = (request) => {
- return new Promise(async (resolve, reject) => {
- const { oauth2 } = request;
- const { callbackUrl, clientId, authorizationUrl, scope } = oauth2;
- const authorizationUrlWithQueryParams = `${authorizationUrl}?client_id=${clientId}&redirect_uri=${callbackUrl}&response_type=code&scope=${scope}`;
- try {
- const code = await authorizeUserInWindow({ authorizeUrl: authorizationUrlWithQueryParams, callbackUrl });
- resolve(code);
- } catch (err) {
- reject(err);
- }
- });
-};
-
-module.exports = {
- resolveOAuth2AuthorizationCodecessToken,
- getOAuth2AuthorizationCode
-};
diff --git a/packages/bruno-electron/src/ipc/network/oauth2-helper.js b/packages/bruno-electron/src/ipc/network/oauth2-helper.js
new file mode 100644
index 000000000..1367523a0
--- /dev/null
+++ b/packages/bruno-electron/src/ipc/network/oauth2-helper.js
@@ -0,0 +1,109 @@
+const { get, cloneDeep } = require('lodash');
+const crypto = require('crypto');
+const { authorizeUserInWindow } = require('./authorize-user-in-window');
+
+const generateCodeVerifier = () => {
+ return crypto.randomBytes(16).toString('hex');
+};
+
+const generateCodeChallenge = (codeVerifier) => {
+ const hash = crypto.createHash('sha256');
+ hash.update(codeVerifier);
+ const base64Hash = hash.digest('base64');
+ return base64Hash.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
+};
+
+// AUTHORIZATION CODE
+
+const resolveOAuth2AuthorizationCodeAccessToken = async (request) => {
+ let codeVerifier = generateCodeVerifier();
+ let codeChallenge = generateCodeChallenge(codeVerifier);
+
+ let requestCopy = cloneDeep(request);
+ const { authorizationCode } = await getOAuth2AuthorizationCode(requestCopy, codeChallenge);
+ const oAuth = get(requestCopy, 'oauth2', {});
+ const { clientId, clientSecret, callbackUrl, scope, pkce } = oAuth;
+ const data = {
+ grant_type: 'authorization_code',
+ code: authorizationCode,
+ redirect_uri: callbackUrl,
+ client_id: clientId,
+ client_secret: clientSecret,
+ scope: scope
+ };
+ if (pkce) {
+ data['code_verifier'] = codeVerifier;
+ }
+
+ const url = requestCopy?.oauth2?.accessTokenUrl;
+ return {
+ data,
+ url
+ };
+};
+
+const getOAuth2AuthorizationCode = (request, codeChallenge) => {
+ return new Promise(async (resolve, reject) => {
+ const { oauth2 } = request;
+ const { callbackUrl, clientId, authorizationUrl, scope, pkce } = oauth2;
+
+ let authorizationUrlWithQueryParams = `${authorizationUrl}?client_id=${clientId}&redirect_uri=${callbackUrl}&response_type=code&scope=${scope}`;
+ if (pkce) {
+ authorizationUrlWithQueryParams += `&code_challenge=${codeChallenge}&code_challenge_method=S256`;
+ }
+ try {
+ const { authorizationCode } = await authorizeUserInWindow({
+ authorizeUrl: authorizationUrlWithQueryParams,
+ callbackUrl
+ });
+ resolve({ authorizationCode });
+ } catch (err) {
+ reject(err);
+ }
+ });
+};
+
+// CLIENT CREDENTIALS
+
+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,
+ scope
+ };
+ const url = requestCopy?.oauth2?.accessTokenUrl;
+ return {
+ data,
+ url
+ };
+};
+
+// PASSWORD CREDENTIALS
+
+const transformPasswordCredentialsRequest = async (request) => {
+ let requestCopy = cloneDeep(request);
+ const oAuth = get(requestCopy, 'oauth2', {});
+ const { username, password, scope } = oAuth;
+ const data = {
+ grant_type: 'password',
+ username,
+ password,
+ scope
+ };
+ const url = requestCopy?.oauth2?.accessTokenUrl;
+ return {
+ data,
+ url
+ };
+};
+
+module.exports = {
+ resolveOAuth2AuthorizationCodeAccessToken,
+ getOAuth2AuthorizationCode,
+ transformClientCredentialsRequest,
+ transformPasswordCredentialsRequest
+};
diff --git a/packages/bruno-electron/src/ipc/network/prepare-collection-request.js b/packages/bruno-electron/src/ipc/network/prepare-collection-request.js
new file mode 100644
index 000000000..5fd630594
--- /dev/null
+++ b/packages/bruno-electron/src/ipc/network/prepare-collection-request.js
@@ -0,0 +1,49 @@
+const { get, each } = require('lodash');
+const { setAuthHeaders } = require('./prepare-request');
+
+const prepareCollectionRequest = (request, collectionRoot) => {
+ const headers = {};
+ let contentTypeDefined = false;
+ let url = request.url;
+
+ // collection headers
+ each(get(collectionRoot, 'request.headers', []), (h) => {
+ if (h.enabled) {
+ headers[h.name] = h.value;
+ if (h.name.toLowerCase() === 'content-type') {
+ contentTypeDefined = true;
+ }
+ }
+ });
+
+ each(request.headers, (h) => {
+ if (h.enabled) {
+ headers[h.name] = h.value;
+ if (h.name.toLowerCase() === 'content-type') {
+ contentTypeDefined = true;
+ }
+ }
+ });
+
+ let axiosRequest = {
+ mode: request?.body?.mode,
+ method: request.method,
+ url,
+ headers,
+ responseType: 'arraybuffer'
+ };
+
+ axiosRequest = setAuthHeaders(axiosRequest, request, collectionRoot);
+
+ if (request.script) {
+ axiosRequest.script = request.script;
+ }
+
+ axiosRequest.vars = request.vars;
+
+ axiosRequest.method = 'POST';
+
+ return axiosRequest;
+};
+
+module.exports = prepareCollectionRequest;
diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js
index b4ec49d5b..4577e733a 100644
--- a/packages/bruno-electron/src/ipc/network/prepare-request.js
+++ b/packages/bruno-electron/src/ipc/network/prepare-request.js
@@ -61,7 +61,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
};
break;
case 'bearer':
- axiosRequest.headers['authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
+ axiosRequest.headers['Authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
break;
case 'digest':
axiosRequest.digestConfig = {
@@ -69,36 +69,6 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
password: get(collectionAuth, 'digest.password')
};
break;
- case 'oauth2':
- const grantType = get(collectionAuth, 'auth.oauth2.grantType');
- switch (grantType) {
- case 'password':
- axiosRequest.oauth2 = {
- grantType: grantType,
- username: get(collectionAuth, 'auth.oauth2.username'),
- password: get(collectionAuth, 'auth.oauth2.password')
- };
- break;
- case 'authorization_code':
- axiosRequest.oauth2 = {
- grantType: grantType,
- callbackUrl: get(collectionAuth, 'auth.oauth2.callbackUrl'),
- authorizationUrl: get(collectionAuth, 'auth.oauth2.authorizationUrl'),
- accessTokenUrl: get(collectionAuth, 'auth.oauth2.accessTokenUrl'),
- clientId: get(collectionAuth, 'auth.oauth2.clientId'),
- clientSecret: get(collectionAuth, 'auth.oauth2.clientSecret'),
- scope: get(collectionAuth, 'auth.oauth2.scope')
- };
- break;
- case 'client_credentials':
- axiosRequest.oauth2 = {
- grantType: grantType,
- clientId: get(collectionAuth, 'auth.oauth2.clientId'),
- clientSecret: get(collectionAuth, 'auth.oauth2.clientSecret')
- };
- break;
- }
- break;
}
}
@@ -121,7 +91,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
};
break;
case 'bearer':
- axiosRequest.headers['authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
+ axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
break;
case 'digest':
axiosRequest.digestConfig = {
@@ -135,8 +105,10 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
case 'password':
axiosRequest.oauth2 = {
grantType: grantType,
+ accessTokenUrl: get(request, 'auth.oauth2.accessTokenUrl'),
username: get(request, 'auth.oauth2.username'),
- password: get(request, 'auth.oauth2.password')
+ password: get(request, 'auth.oauth2.password'),
+ scope: get(request, 'auth.oauth2.scope')
};
break;
case 'authorization_code':
@@ -147,14 +119,17 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
accessTokenUrl: get(request, 'auth.oauth2.accessTokenUrl'),
clientId: get(request, 'auth.oauth2.clientId'),
clientSecret: get(request, 'auth.oauth2.clientSecret'),
- scope: get(request, 'auth.oauth2.scope')
+ scope: get(request, 'auth.oauth2.scope'),
+ pkce: get(request, 'auth.oauth2.pkce')
};
break;
case 'client_credentials':
axiosRequest.oauth2 = {
grantType: grantType,
+ accessTokenUrl: get(request, 'auth.oauth2.accessTokenUrl'),
clientId: get(request, 'auth.oauth2.clientId'),
- clientSecret: get(request, 'auth.oauth2.clientSecret')
+ clientSecret: get(request, 'auth.oauth2.clientSecret'),
+ scope: get(request, 'auth.oauth2.scope')
};
break;
}
diff --git a/packages/bruno-js/src/bruno-request.js b/packages/bruno-js/src/bruno-request.js
index afbf97873..909adf92a 100644
--- a/packages/bruno-js/src/bruno-request.js
+++ b/packages/bruno-js/src/bruno-request.js
@@ -20,6 +20,22 @@ class BrunoRequest {
return this.req.method;
}
+ getAuthMode() {
+ if (this.req?.oauth2) {
+ return 'oauth2';
+ } else if (this.headers?.['Authorization']?.startsWith('Bearer')) {
+ return 'bearer';
+ } else if (this.headers?.['Authorization']?.startsWith('Basic') || this.req?.auth?.username) {
+ return 'basic';
+ } else if (this.req?.awsv4) {
+ return 'awsv4';
+ } else if (this.req?.digestConfig) {
+ return 'digest';
+ } else {
+ return 'none';
+ }
+ }
+
setMethod(method) {
this.req.method = method;
}
diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js
index 71c3e9e6c..1586838b9 100644
--- a/packages/bruno-lang/v2/src/bruToJson.js
+++ b/packages/bruno-lang/v2/src/bruToJson.js
@@ -392,14 +392,17 @@ const sem = grammar.createSemantics().addAttribute('ast', {
const clientIdKey = _.find(auth, { name: 'client_id' });
const clientSecretKey = _.find(auth, { name: 'client_secret' });
const scopeKey = _.find(auth, { name: 'scope' });
+ const pkceKey = _.find(auth, { name: 'pkce' });
return {
auth: {
oauth2:
grantTypeKey?.value && grantTypeKey?.value == 'password'
? {
grantType: grantTypeKey ? grantTypeKey.value : '',
+ accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '',
username: usernameKey ? usernameKey.value : '',
- password: passwordKey ? passwordKey.value : ''
+ password: passwordKey ? passwordKey.value : '',
+ scope: scopeKey ? scopeKey.value : ''
}
: grantTypeKey?.value && grantTypeKey?.value == 'authorization_code'
? {
@@ -409,13 +412,16 @@ const sem = grammar.createSemantics().addAttribute('ast', {
accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '',
clientId: clientIdKey ? clientIdKey.value : '',
clientSecret: clientSecretKey ? clientSecretKey.value : '',
- scope: scopeKey ? scopeKey.value : ''
+ scope: scopeKey ? scopeKey.value : '',
+ pkce: pkceKey ? JSON.parse(pkceKey?.value || false) : false
}
: grantTypeKey?.value && grantTypeKey?.value == 'client_credentials'
? {
grantType: grantTypeKey ? grantTypeKey.value : '',
+ accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '',
clientId: clientIdKey ? clientIdKey.value : '',
- clientSecret: clientSecretKey ? clientSecretKey.value : ''
+ clientSecret: clientSecretKey ? clientSecretKey.value : '',
+ scope: scopeKey ? scopeKey.value : ''
}
: {}
}
diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js
index c24f6e6ae..e408d4d95 100644
--- a/packages/bruno-lang/v2/src/collectionBruToJson.js
+++ b/packages/bruno-lang/v2/src/collectionBruToJson.js
@@ -4,7 +4,7 @@ const { outdentString } = require('../../v1/src/utils');
const grammar = ohm.grammar(`Bru {
BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)*
- auths = authawsv4 | authbasic | authbearer | authdigest
+ auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2
nl = "\\r"? "\\n"
st = " " | "\\t"
@@ -42,6 +42,7 @@ const grammar = ohm.grammar(`Bru {
authbasic = "auth:basic" dictionary
authbearer = "auth:bearer" dictionary
authdigest = "auth:digest" dictionary
+ authOAuth2 = "auth:oauth2" dictionary
script = scriptreq | scriptres
scriptreq = "script:pre-request" st* "{" nl* textblock tagend
@@ -242,6 +243,52 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}
};
},
+ authOAuth2(_1, dictionary) {
+ const auth = mapPairListToKeyValPairs(dictionary.ast, false);
+ const grantTypeKey = _.find(auth, { name: 'grant_type' });
+ const usernameKey = _.find(auth, { name: 'username' });
+ const passwordKey = _.find(auth, { name: 'password' });
+ const callbackUrlKey = _.find(auth, { name: 'callback_url' });
+ const authorizationUrlKey = _.find(auth, { name: 'authorization_url' });
+ const accessTokenUrlKey = _.find(auth, { name: 'access_token_url' });
+ const clientIdKey = _.find(auth, { name: 'client_id' });
+ const clientSecretKey = _.find(auth, { name: 'client_secret' });
+ const scopeKey = _.find(auth, { name: 'scope' });
+ const pkceKey = _.find(auth, { name: 'pkce' });
+ return {
+ auth: {
+ oauth2:
+ grantTypeKey?.value && grantTypeKey?.value == 'password'
+ ? {
+ grantType: grantTypeKey ? grantTypeKey.value : '',
+ accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '',
+ username: usernameKey ? usernameKey.value : '',
+ password: passwordKey ? passwordKey.value : '',
+ scope: scopeKey ? scopeKey.value : ''
+ }
+ : grantTypeKey?.value && grantTypeKey?.value == 'authorization_code'
+ ? {
+ grantType: grantTypeKey ? grantTypeKey.value : '',
+ callbackUrl: callbackUrlKey ? callbackUrlKey.value : '',
+ authorizationUrl: authorizationUrlKey ? authorizationUrlKey.value : '',
+ accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '',
+ clientId: clientIdKey ? clientIdKey.value : '',
+ clientSecret: clientSecretKey ? clientSecretKey.value : '',
+ scope: scopeKey ? scopeKey.value : '',
+ pkce: pkceKey ? JSON.parse(pkceKey?.value || false) : false
+ }
+ : grantTypeKey?.value && grantTypeKey?.value == 'client_credentials'
+ ? {
+ grantType: grantTypeKey ? grantTypeKey.value : '',
+ accessTokenUrl: accessTokenUrlKey ? accessTokenUrlKey.value : '',
+ clientId: clientIdKey ? clientIdKey.value : '',
+ clientSecret: clientSecretKey ? clientSecretKey.value : '',
+ scope: scopeKey ? scopeKey.value : ''
+ }
+ : {}
+ }
+ };
+ },
varsreq(_1, dictionary) {
const vars = mapPairListToKeyValPairs(dictionary.ast);
_.each(vars, (v) => {
diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js
index bd0eec919..e9b06691f 100644
--- a/packages/bruno-lang/v2/src/jsonToBru.js
+++ b/packages/bruno-lang/v2/src/jsonToBru.js
@@ -131,8 +131,10 @@ ${indentString(`password: ${auth?.digest?.password || ''}`)}
case 'password':
bru += `auth:oauth2 {
${indentString(`grant_type: password`)}
+${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)}
${indentString(`username: ${auth?.oauth2?.username || ''}`)}
${indentString(`password: ${auth?.oauth2?.password || ''}`)}
+${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
}
`;
@@ -146,6 +148,7 @@ ${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)}
${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)}
${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)}
${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
+${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)}
}
`;
@@ -153,8 +156,10 @@ ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
case 'client_credentials':
bru += `auth:oauth2 {
${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(`scope: ${auth?.oauth2?.scope || ''}`)}
}
`;
diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js
index 08a3abad5..4d7e71f14 100644
--- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js
+++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js
@@ -114,6 +114,47 @@ ${indentString(`password: ${auth.digest.password}`)}
`;
}
+ if (auth && auth.oauth2) {
+ switch (auth?.oauth2?.grantType) {
+ case 'password':
+ bru += `auth:oauth2 {
+${indentString(`grant_type: password`)}
+${indentString(`access_token_url: ${auth?.oauth2?.accessTokenUrl || ''}`)}
+${indentString(`username: ${auth?.oauth2?.username || ''}`)}
+${indentString(`password: ${auth?.oauth2?.password || ''}`)}
+${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
+}
+
+`;
+ break;
+ case 'authorization_code':
+ bru += `auth:oauth2 {
+${indentString(`grant_type: authorization_code`)}
+${indentString(`callback_url: ${auth?.oauth2?.callbackUrl || ''}`)}
+${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(`scope: ${auth?.oauth2?.scope || ''}`)}
+${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)}
+}
+
+`;
+ break;
+ case 'client_credentials':
+ bru += `auth:oauth2 {
+${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(`scope: ${auth?.oauth2?.scope || ''}`)}
+}
+
+`;
+ break;
+ }
+ }
+
let reqvars = _.get(vars, 'req');
let resvars = _.get(vars, 'res');
if (reqvars && reqvars.length) {
diff --git a/packages/bruno-lang/v2/tests/fixtures/request.bru b/packages/bruno-lang/v2/tests/fixtures/request.bru
index 94eb02fe9..56800154c 100644
--- a/packages/bruno-lang/v2/tests/fixtures/request.bru
+++ b/packages/bruno-lang/v2/tests/fixtures/request.bru
@@ -47,9 +47,9 @@ auth:digest {
auth:oauth2 {
grant_type: authorization_code
- callback_url: http://localhost:8080/api/auth/oauth2/ac/callback
- authorization_url: http://localhost:8080/api/auth/oauth2/ac/authorize
- access_token_url: http://localhost:8080/api/auth/oauth2/ac/token
+ 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
scope: read write
diff --git a/packages/bruno-lang/v2/tests/fixtures/request.json b/packages/bruno-lang/v2/tests/fixtures/request.json
index c7987839b..3f5f2b599 100644
--- a/packages/bruno-lang/v2/tests/fixtures/request.json
+++ b/packages/bruno-lang/v2/tests/fixtures/request.json
@@ -68,9 +68,9 @@
"grantType": "authorization_code",
"clientId": "client_id_1",
"clientSecret": "client_secret_1",
- "authorizationUrl": "http://localhost:8080/api/auth/oauth2/ac/authorize",
- "callbackUrl": "http://localhost:8080/api/auth/oauth2/ac/callback",
- "accessTokenUrl": "http://localhost:8080/api/auth/oauth2/ac/token",
+ "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"
}
},
diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js
index b3c5e8dc5..bbdda8d6f 100644
--- a/packages/bruno-schema/src/collections/index.js
+++ b/packages/bruno-schema/src/collections/index.js
@@ -144,7 +144,7 @@ const oauth2Schema = Yup.object({
otherwise: Yup.string().nullable().strip()
}),
accessTokenUrl: Yup.string().when('grantType', {
- is: (val) => ['authorization_code'].includes(val),
+ is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val),
then: Yup.string().nullable(),
otherwise: Yup.string().nullable().strip()
}),
@@ -159,9 +159,14 @@ const oauth2Schema = Yup.object({
otherwise: Yup.string().nullable().strip()
}),
scope: Yup.string().when('grantType', {
- is: (val) => ['authorization_code'].includes(val),
+ is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val),
then: Yup.string().nullable(),
otherwise: Yup.string().nullable().strip()
+ }),
+ pkce: Yup.boolean().when('grantType', {
+ is: (val) => ['authorization_code'].includes(val),
+ then: Yup.boolean().defined(),
+ otherwise: Yup.boolean()
})
})
.noUnknown(true)
diff --git a/packages/bruno-tests/collection/collection.bru b/packages/bruno-tests/collection/collection.bru
index dfcac9859..a60283cd7 100644
--- a/packages/bruno-tests/collection/collection.bru
+++ b/packages/bruno-tests/collection/collection.bru
@@ -3,16 +3,7 @@ headers {
}
auth {
- mode: bearer
-}
-
-auth:basic {
- username: bruno
- password: {{basicAuthPassword}}
-}
-
-auth:bearer {
- token: {{bearer_auth_token}}
+ mode: none
}
docs {
diff --git a/packages/bruno-tests/collection/environments/Local.bru b/packages/bruno-tests/collection/environments/Local.bru
index 86e79139d..991077d97 100644
--- a/packages/bruno-tests/collection/environments/Local.bru
+++ b/packages/bruno-tests/collection/environments/Local.bru
@@ -4,11 +4,11 @@ vars {
basic_auth_password: della
client_id: client_id_1
client_secret: client_secret_1
- auth_url: http://localhost:8080/api/auth/oauth2/ac/authorize
- callback_url: http://localhost:8080/api/auth/oauth2/ac/callback
- access_token_url: http://localhost:8080/api/auth/oauth2/ac/token
- ropc_username: foo
- ropc_password: bar
+ auth_url: http://localhost:8080/api/auth/oauth2/authorization_code/authorize
+ callback_url: http://localhost:8080/api/auth/oauth2/authorization_code/callback
+ access_token_url: http://localhost:8080/api/auth/oauth2/authorization_code/token
+ passwordCredentials_username: foo
+ passwordCredentials_password: bar
github_authorize_url: https://github.com/login/oauth/authorize
github_access_token_url: https://github.com/login/oauth/access_token
google_auth_url: https://accounts.google.com/o/oauth2/auth
@@ -21,8 +21,8 @@ vars:secret [
google_client_id,
google_client_secret,
github_authorization_code,
- ropc_access_token,
- cc_access_token,
- ac_access_token,
+ passwordCredentials_access_token,
+ client_credentials_access_token,
+ authorization_code_access_token,
github_access_token
]
diff --git a/packages/bruno-tests/collection_level_oauth2/.gitignore b/packages/bruno-tests/collection_level_oauth2/.gitignore
new file mode 100644
index 000000000..1e18f275e
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/.gitignore
@@ -0,0 +1 @@
+!.env
\ No newline at end of file
diff --git a/packages/bruno-tests/collection_level_oauth2/.nvmrc b/packages/bruno-tests/collection_level_oauth2/.nvmrc
new file mode 100644
index 000000000..0828ab794
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/.nvmrc
@@ -0,0 +1 @@
+v18
\ No newline at end of file
diff --git a/packages/bruno-tests/collection_level_oauth2/bruno.json b/packages/bruno-tests/collection_level_oauth2/bruno.json
new file mode 100644
index 000000000..17f1d8ea0
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/bruno.json
@@ -0,0 +1,18 @@
+{
+ "version": "1",
+ "name": "collection_level_oauth2",
+ "type": "collection",
+ "scripts": {
+ "moduleWhitelist": ["crypto"],
+ "filesystemAccess": {
+ "allow": true
+ }
+ },
+ "clientCertificates": {
+ "enabled": true,
+ "certs": []
+ },
+ "presets": {
+ "requestType": "http"
+ }
+}
diff --git a/packages/bruno-tests/collection_level_oauth2/collection.bru b/packages/bruno-tests/collection_level_oauth2/collection.bru
new file mode 100644
index 000000000..a205016b1
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/collection.bru
@@ -0,0 +1,30 @@
+headers {
+ check: again
+}
+
+auth {
+ mode: oauth2
+}
+
+auth:oauth2 {
+ grant_type: authorization_code
+ callback_url: {{authorization_code_callback_url}}
+ authorization_url: {{authorization_code_authorize_url}}
+ access_token_url: {{authorization_code_access_token_url}}
+ client_id: {{client_id}}
+ client_secret: {{client_secret}}
+ scope:
+ pkce: true
+}
+
+script:post-response {
+ if(req.getAuthMode() == 'oauth2' && res.body.access_token) {
+ bru.setEnvVar('access_token_set_by_collection',res.body.access_token)
+ }
+}
+
+docs {
+ # bruno-testbench 🐶
+
+ This is a test collection that I am using to test various functionalities around bruno
+}
diff --git a/packages/bruno-tests/collection_level_oauth2/environments/Local.bru b/packages/bruno-tests/collection_level_oauth2/environments/Local.bru
new file mode 100644
index 000000000..99658dac6
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/environments/Local.bru
@@ -0,0 +1,34 @@
+vars {
+ host: http://localhost:8080
+ bearer_auth_token: your_secret_token
+ basic_auth_password: della
+ client_id: client_id_1
+ client_secret: client_secret_1
+ password_credentials_access_token_url: http://localhost:8080/api/auth/oauth2/password_credentials/token
+ password_credentials_username: foo
+ password_credentials_password: bar
+ password_credentials_scope:
+ authorization_code_authorize_url: http://localhost:8080/api/auth/oauth2/authorization_code/authorize
+ authorization_code_callback_url: http://localhost:8080/api/auth/oauth2/authorization_code/callback
+ authorization_code_access_token_url: http://localhost:8080/api/auth/oauth2/authorization_code/token
+ authorization_code_google_auth_url: https://accounts.google.com/o/oauth2/auth
+ authorization_code_google_access_token_url: https://accounts.google.com/o/oauth2/token
+ authorization_code_google_scope: https://www.googleapis.com/auth/userinfo.email
+ authorization_code_github_authorize_url: https://github.com/login/oauth/authorize
+ authorization_code_github_access_token_url: https://github.com/login/oauth/access_token
+ authorization_code_access_token: null
+ client_credentials_access_token_url: http://localhost:8080/api/auth/oauth2/client_credentials/token
+ client_credentials_client_id: client_id_1
+ client_credentials_client_secret: client_secret_1
+ client_credentials_scope: admin
+ client_credentials_access_token: 9f1b1874f1e79b48a46d65569d830bbb
+ common_access_token: 9f1b1874f1e79b48a46d65569d830bbb
+}
+vars:secret [
+ authorization_code_google_client_id,
+ authorization_code_google_client_secret,
+ authorization_code_github_client_secret,
+ authorization_code_github_client_id,
+ authorization_code_github_authorization_code,
+ authorization_code_github_access_token
+]
diff --git a/packages/bruno-tests/collection_level_oauth2/environments/Prod.bru b/packages/bruno-tests/collection_level_oauth2/environments/Prod.bru
new file mode 100644
index 000000000..e6286f3b6
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/environments/Prod.bru
@@ -0,0 +1,8 @@
+vars {
+ host: https://testbench-sanity.usebruno.com
+ bearer_auth_token: your_secret_token
+ basic_auth_password: della
+ env.var1: envVar1
+ env-var2: envVar2
+ bark: {{process.env.PROC_ENV_VAR}}
+}
diff --git a/packages/bruno-tests/collection_level_oauth2/package-lock.json b/packages/bruno-tests/collection_level_oauth2/package-lock.json
new file mode 100644
index 000000000..717181ec3
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/package-lock.json
@@ -0,0 +1,30 @@
+{
+ "name": "@usebruno/test-collection",
+ "version": "0.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@usebruno/test-collection",
+ "version": "0.0.1",
+ "dependencies": {
+ "@faker-js/faker": "^8.4.0"
+ }
+ },
+ "node_modules/@faker-js/faker": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.0.tgz",
+ "integrity": "sha512-htW87352wzUCdX1jyUQocUcmAaFqcR/w082EC8iP/gtkF0K+aKcBp0hR5Arb7dzR8tQ1TrhE9DNa5EbJELm84w==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fakerjs"
+ }
+ ],
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0",
+ "npm": ">=6.14.13"
+ }
+ }
+ }
+}
diff --git a/packages/bruno-tests/collection_level_oauth2/package.json b/packages/bruno-tests/collection_level_oauth2/package.json
new file mode 100644
index 000000000..23621129b
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "@usebruno/test-collection",
+ "version": "0.0.1",
+ "dependencies": {
+ "@faker-js/faker": "^8.4.0"
+ }
+}
diff --git a/packages/bruno-tests/collection_level_oauth2/readme.md b/packages/bruno-tests/collection_level_oauth2/readme.md
new file mode 100644
index 000000000..a41582d22
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/readme.md
@@ -0,0 +1,3 @@
+# bruno-tests collection
+
+API Collection to run sanity tests on Bruno CLI.
diff --git a/packages/bruno-tests/collection_level_oauth2/resource.bru b/packages/bruno-tests/collection_level_oauth2/resource.bru
new file mode 100644
index 000000000..53b67e2c3
--- /dev/null
+++ b/packages/bruno-tests/collection_level_oauth2/resource.bru
@@ -0,0 +1,15 @@
+meta {
+ name: resource
+ type: http
+ seq: 2
+}
+
+post {
+ url: {{host}}/api/auth/oauth2/authorization_code/resource?token={{access_token_set_by_collection}}
+ body: json
+ auth: none
+}
+
+query {
+ token: {{access_token_set_by_collection}}
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/github token with authorize.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/github token with authorize.bru
deleted file mode 100644
index c18d2c6ed..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/github token with authorize.bru
+++ /dev/null
@@ -1,25 +0,0 @@
-meta {
- name: github token with authorize
- type: http
- seq: 1
-}
-
-post {
- url: github.com
- body: none
- auth: oauth2
-}
-
-auth:oauth2 {
- grant_type: authorization_code
- callback_url: {{callback_url}}
- authorization_url: {{github_authorize_url}}
- access_token_url: {{github_access_token_url}}
- client_id: {{github_client_id}}
- client_secret: {{github_client_secret}}
- scope: repo,gist
-}
-
-script:post-response {
- bru.setEnvVar('github_access_token',res.body.split('access_token=')[1]?.split('&scope')[0]);
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/google token with authorize.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/google token with authorize.bru
deleted file mode 100644
index 93ea7975e..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/google token with authorize.bru
+++ /dev/null
@@ -1,25 +0,0 @@
-meta {
- name: google token with authorize
- type: http
- seq: 4
-}
-
-post {
- url:
- body: none
- auth: oauth2
-}
-
-auth:oauth2 {
- grant_type: authorization_code
- callback_url: {{callback_url}}
- authorization_url: {{google_auth_url}}
- access_token_url: {{google_access_token_url}}
- client_id: {{google_client_id}}
- client_secret: {{google_client_secret}}
- scope: {{google_scope}}
-}
-
-script:post-response {
- bru.setEnvVar('ac_access_token', res.body.access_token);
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/resource.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/resource.bru
deleted file mode 100644
index ead30ec6b..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/resource.bru
+++ /dev/null
@@ -1,27 +0,0 @@
-meta {
- name: resource
- type: http
- seq: 3
-}
-
-post {
- url: {{host}}/api/auth/oauth2/ac/resource?token={{ac_access_token}}
- body: json
- auth: none
-}
-
-query {
- token: {{ac_access_token}}
-}
-
-auth:bearer {
- token:
-}
-
-body:json {
- {
- "code": "eb30dbf783b65bec4539ee1dcb068606",
- "client_id": "{{client_id}}",
- "client_secret": "{{client_secret}}"
- }
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/token with authorize.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/token with authorize.bru
deleted file mode 100644
index e42fd7c77..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/ac/token with authorize.bru
+++ /dev/null
@@ -1,25 +0,0 @@
-meta {
- name: token with authorize
- type: http
- seq: 4
-}
-
-post {
- url:
- body: none
- auth: oauth2
-}
-
-auth:oauth2 {
- grant_type: authorization_code
- callback_url: {{callback_url}}
- authorization_url: {{auth_url}}
- access_token_url: {{access_token_url}}
- client_id: {{client_id}}
- client_secret: {{client_secret}}
- scope:
-}
-
-script:post-response {
- bru.setEnvVar('ac_access_token', res.body.access_token);
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/github token with authorize.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/github token with authorize.bru
new file mode 100644
index 000000000..2114ccf45
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/github token with authorize.bru
@@ -0,0 +1,25 @@
+meta {
+ name: github token with authorize
+ type: http
+ seq: 1
+}
+
+post {
+ url:
+ body: none
+ auth: oauth2
+}
+
+auth:oauth2 {
+ grant_type: authorization_code
+ callback_url: {{authorization_code_callback_url}}
+ authorization_url: {{authorization_code_github_authorize_url}}
+ access_token_url: {{authorization_code_github_access_token_url}}
+ client_id: {{authorization_code_github_client_id}}
+ client_secret: {{authorization_code_github_client_secret}}
+ scope: repo,gist
+}
+
+script:post-response {
+ bru.setEnvVar('github_access_token',res.body.split('access_token=')[1]?.split('&scope')[0]);
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/google token with authorize.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/google token with authorize.bru
new file mode 100644
index 000000000..abace9d0c
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/google token with authorize.bru
@@ -0,0 +1,25 @@
+meta {
+ name: google token with authorize
+ type: http
+ seq: 4
+}
+
+post {
+ url:
+ body: none
+ auth: oauth2
+}
+
+auth:oauth2 {
+ grant_type: authorization_code
+ callback_url: {{authorization_code_callback_url}}
+ authorization_url: {{authorization_code_google_auth_url}}
+ access_token_url: {{authorization_code_google_access_token_url}}
+ client_id: {{authorization_code_google_client_id}}
+ client_secret: {{authorization_code_google_client_secret}}
+ scope: {{authorization_code_google_scope}}
+}
+
+script:post-response {
+ bru.setEnvVar('authorization_code_access_token', res.body.access_token);
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/resource.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/resource.bru
new file mode 100644
index 000000000..a1f355fca
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/resource.bru
@@ -0,0 +1,15 @@
+meta {
+ name: resource
+ type: http
+ seq: 3
+}
+
+post {
+ url: {{host}}/api/auth/oauth2/authorization_code/resource?token={{authorization_code_access_token}}
+ body: json
+ auth: none
+}
+
+query {
+ token: {{authorization_code_access_token}}
+}
\ No newline at end of file
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/token with authorize.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/token with authorize.bru
new file mode 100644
index 000000000..2b73c4da7
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/authorization_code/token with authorize.bru
@@ -0,0 +1,26 @@
+meta {
+ name: token with authorize
+ type: http
+ seq: 4
+}
+
+post {
+ url:
+ body: none
+ auth: oauth2
+}
+
+auth:oauth2 {
+ grant_type: authorization_code
+ callback_url: {{authorization_code_callback_url}}
+ authorization_url: {{authorization_code_authorize_url}}
+ access_token_url: {{authorization_code_access_token_url}}
+ client_id: {{client_id}}
+ client_secret: {{client_secret}}
+ scope:
+ pkce: true
+}
+
+script:post-response {
+ bru.setEnvVar('authorization_code_access_token', res.body.access_token);
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/cc/resource.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/cc/resource.bru
deleted file mode 100644
index c4a1ce399..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/cc/resource.bru
+++ /dev/null
@@ -1,15 +0,0 @@
-meta {
- name: resource
- type: http
- seq: 2
-}
-
-get {
- url: {{host}}/api/auth/oauth2/cc/resource?token={{cc_access_token}}
- body: none
- auth: none
-}
-
-query {
- token: {{cc_access_token}}
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/cc/token.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/cc/token.bru
deleted file mode 100644
index 13987b2eb..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/cc/token.bru
+++ /dev/null
@@ -1,21 +0,0 @@
-meta {
- name: token
- type: http
- seq: 1
-}
-
-post {
- url: {{host}}/api/auth/oauth2/cc/token
- body: none
- auth: oauth2
-}
-
-auth:oauth2 {
- grant_type: client_credentials
- client_id: {{client_id}}
- client_secret: {{client_secret}}
-}
-
-script:post-response {
- bru.setEnvVar('cc_access_token', res.body.access_token);
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/client_credentials/resource.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/client_credentials/resource.bru
new file mode 100644
index 000000000..c4b28eea3
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/client_credentials/resource.bru
@@ -0,0 +1,15 @@
+meta {
+ name: resource
+ type: http
+ seq: 2
+}
+
+get {
+ url: {{host}}/api/auth/oauth2/client_credentials/resource?token={{client_credentials_access_token}}
+ body: none
+ auth: none
+}
+
+query {
+ token: {{client_credentials_access_token}}
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/client_credentials/token.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/client_credentials/token.bru
new file mode 100644
index 000000000..e0d11bbf0
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/client_credentials/token.bru
@@ -0,0 +1,23 @@
+meta {
+ name: token
+ type: http
+ seq: 1
+}
+
+post {
+ url:
+ body: none
+ auth: oauth2
+}
+
+auth:oauth2 {
+ grant_type: client_credentials
+ access_token_url: {{client_credentials_access_token_url}}
+ client_id: {{client_credentials_client_id}}
+ client_secret: {{client_credentials_client_secret}}
+ scope: {{client_credentials_scope}}
+}
+
+script:post-response {
+ bru.setEnvVar('client_credentials_access_token', res.body.access_token);
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/password_credentials/resource.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/password_credentials/resource.bru
new file mode 100644
index 000000000..b0e9d4388
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/password_credentials/resource.bru
@@ -0,0 +1,15 @@
+meta {
+ name: resource
+ type: http
+ seq: 2
+}
+
+post {
+ url: {{host}}/api/auth/oauth2/password_credentials/resource
+ body: none
+ auth: bearer
+}
+
+auth:bearer {
+ token: {{passwordCredentials_access_token}}
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/password_credentials/token.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/password_credentials/token.bru
new file mode 100644
index 000000000..a4eee5463
--- /dev/null
+++ b/packages/bruno-tests/collection_oauth2/auth/oauth2/password_credentials/token.bru
@@ -0,0 +1,23 @@
+meta {
+ name: token
+ type: http
+ seq: 1
+}
+
+post {
+ url:
+ body: none
+ auth: oauth2
+}
+
+auth:oauth2 {
+ grant_type: password
+ access_token_url: {{password_credentials_access_token_url}}
+ username: {{password_credentials_username}}
+ password: {{password_credentials_password}}
+ scope:
+}
+
+script:post-response {
+ bru.setEnvVar('passwordCredentials_access_token', res.body.access_token);
+}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/ropc/resource.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/ropc/resource.bru
deleted file mode 100644
index 1395250ee..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/ropc/resource.bru
+++ /dev/null
@@ -1,15 +0,0 @@
-meta {
- name: resource
- type: http
- seq: 2
-}
-
-post {
- url: {{host}}/api/auth/oauth2/ropc/resource
- body: none
- auth: bearer
-}
-
-auth:bearer {
- token: {{ropc_access_token}}
-}
diff --git a/packages/bruno-tests/collection_oauth2/auth/oauth2/ropc/token.bru b/packages/bruno-tests/collection_oauth2/auth/oauth2/ropc/token.bru
deleted file mode 100644
index 495655ab3..000000000
--- a/packages/bruno-tests/collection_oauth2/auth/oauth2/ropc/token.bru
+++ /dev/null
@@ -1,21 +0,0 @@
-meta {
- name: token
- type: http
- seq: 1
-}
-
-post {
- url: {{host}}/api/auth/oauth2/ropc/token
- body: none
- auth: oauth2
-}
-
-auth:oauth2 {
- grant_type: password
- username: {{ropc_username}}
- password: {{ropc_password}}
-}
-
-script:post-response {
- bru.setEnvVar('ropc_access_token', res.body.access_token);
-}
diff --git a/packages/bruno-tests/collection_oauth2/bruno.json b/packages/bruno-tests/collection_oauth2/bruno.json
index 79602ccd3..66949e685 100644
--- a/packages/bruno-tests/collection_oauth2/bruno.json
+++ b/packages/bruno-tests/collection_oauth2/bruno.json
@@ -1,19 +1,7 @@
{
"version": "1",
- "name": "bruno-testbench",
+ "name": "collection_oauth2",
"type": "collection",
- "proxy": {
- "enabled": false,
- "protocol": "http",
- "hostname": "{{proxyHostname}}",
- "port": 4000,
- "auth": {
- "enabled": false,
- "username": "anoop",
- "password": "password"
- },
- "bypassProxy": ""
- },
"scripts": {
"moduleWhitelist": ["crypto"],
"filesystemAccess": {
@@ -25,7 +13,6 @@
"certs": []
},
"presets": {
- "requestType": "http",
- "requestUrl": "http://localhost:6000"
+ "requestType": "http"
}
}
diff --git a/packages/bruno-tests/collection_oauth2/collection.bru b/packages/bruno-tests/collection_oauth2/collection.bru
index e31b64995..a60283cd7 100644
--- a/packages/bruno-tests/collection_oauth2/collection.bru
+++ b/packages/bruno-tests/collection_oauth2/collection.bru
@@ -6,15 +6,6 @@ auth {
mode: none
}
-auth:basic {
- username: bruno
- password: {{basicAuthPassword}}
-}
-
-auth:bearer {
- token: {{bearerAuthToken}}
-}
-
docs {
# bruno-testbench 🐶
diff --git a/packages/bruno-tests/collection_oauth2/environments/Local.bru b/packages/bruno-tests/collection_oauth2/environments/Local.bru
index 99fff5991..396c97c61 100644
--- a/packages/bruno-tests/collection_oauth2/environments/Local.bru
+++ b/packages/bruno-tests/collection_oauth2/environments/Local.bru
@@ -4,23 +4,29 @@ vars {
basic_auth_password: della
client_id: client_id_1
client_secret: client_secret_1
- auth_url: http://localhost:8080/api/auth/oauth2/ac/authorize
- callback_url: http://localhost:8080/api/auth/oauth2/ac/callback
- access_token_url: http://localhost:8080/api/auth/oauth2/ac/token
- ropc_username: foo
- ropc_password: bar
- github_authorize_url: https://github.com/login/oauth/authorize
- github_access_token_url: https://github.com/login/oauth/access_token
- google_auth_url: https://accounts.google.com/o/oauth2/auth
- google_access_token_url: https://accounts.google.com/o/oauth2/token
- google_scope: https://www.googleapis.com/auth/userinfo.email
+ password_credentials_access_token_url: http://localhost:8080/api/auth/oauth2/password_credentials/token
+ password_credentials_username: foo
+ password_credentials_password: bar
+ password_credentials_scope:
+ authorization_code_authorize_url: http://localhost:8080/api/auth/oauth2/authorization_code/authorize
+ authorization_code_callback_url: http://localhost:8080/api/auth/oauth2/authorization_code/callback
+ authorization_code_access_token_url: http://localhost:8080/api/auth/oauth2/authorization_code/token
+ authorization_code_google_auth_url: https://accounts.google.com/o/oauth2/auth
+ authorization_code_google_access_token_url: https://accounts.google.com/o/oauth2/token
+ authorization_code_google_scope: https://www.googleapis.com/auth/userinfo.email
+ authorization_code_github_authorize_url: https://github.com/login/oauth/authorize
+ authorization_code_github_access_token_url: https://github.com/login/oauth/access_token
+ authorization_code_access_token: null
+ client_credentials_access_token_url: http://localhost:8080/api/auth/oauth2/client_credentials/token
+ client_credentials_client_id: client_id_1
+ client_credentials_client_secret: client_secret_1
+ client_credentials_scope: admin
}
vars:secret [
- github_client_secret,
- github_client_id,
- google_client_id,
- google_client_secret,
- github_authorization_code,
- github_access_token,
- ac_access_token
+ authorization_code_google_client_id,
+ authorization_code_google_client_secret,
+ authorization_code_github_client_secret,
+ authorization_code_github_client_id,
+ authorization_code_github_authorization_code,
+ authorization_code_github_access_token
]
diff --git a/packages/bruno-tests/src/auth/index.js b/packages/bruno-tests/src/auth/index.js
index 0b5dc7f63..6d6ebfb55 100644
--- a/packages/bruno-tests/src/auth/index.js
+++ b/packages/bruno-tests/src/auth/index.js
@@ -4,13 +4,13 @@ const router = express.Router();
const authBearer = require('./bearer');
const authBasic = require('./basic');
const authCookie = require('./cookie');
-const authOAuth2Ropc = require('./oauth2/ropc');
-const authOAuth2AuthorizationCode = require('./oauth2/ac');
-const authOAuth2Cc = require('./oauth2/cc');
+const authOAuth2PasswordCredentials = require('./oauth2/passwordCredentials');
+const authOAuth2AuthorizationCode = require('./oauth2/authorizationCode');
+const authOAuth2ClientCredentials = require('./oauth2/clientCredentials');
-router.use('/oauth2/ropc', authOAuth2Ropc);
-router.use('/oauth2/ac', authOAuth2AuthorizationCode);
-router.use('/oauth2/cc', authOAuth2Cc);
+router.use('/oauth2/password_credentials', authOAuth2PasswordCredentials);
+router.use('/oauth2/authorization_code', authOAuth2AuthorizationCode);
+router.use('/oauth2/client_credentials', authOAuth2ClientCredentials);
router.use('/bearer', authBearer);
router.use('/basic', authBasic);
router.use('/cookie', authCookie);
diff --git a/packages/bruno-tests/src/auth/oauth2/ac.js b/packages/bruno-tests/src/auth/oauth2/authorizationCode.js
similarity index 78%
rename from packages/bruno-tests/src/auth/oauth2/ac.js
rename to packages/bruno-tests/src/auth/oauth2/authorizationCode.js
index 840c2a778..1cc089a2c 100644
--- a/packages/bruno-tests/src/auth/oauth2/ac.js
+++ b/packages/bruno-tests/src/auth/oauth2/authorizationCode.js
@@ -17,8 +17,16 @@ function generateUniqueString() {
return crypto.randomBytes(16).toString('hex');
}
+const generateCodeChallenge = (codeVerifier) => {
+ const hash = crypto.createHash('sha256');
+ hash.update(codeVerifier);
+ const base64Hash = hash.digest('base64');
+ return base64Hash.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
+};
+
router.get('/authorize', (req, res) => {
- const { response_type, client_id, redirect_uri } = req.query;
+ const { response_type, client_id, redirect_uri, code_challenge } = req.query;
+ console.log('authorization code authorize', req.query);
if (response_type !== 'code') {
return res.status(401).json({ error: 'Invalid Response type, expected "code"' });
}
@@ -37,7 +45,8 @@ router.get('/authorize', (req, res) => {
authCodes.push({
authCode: authorization_code,
client_id,
- redirect_uri
+ redirect_uri,
+ code_challenge
});
const redirectUrl = `${redirect_uri}?code=${authorization_code}`;
@@ -72,6 +81,7 @@ router.get('/authorize', (req, res) => {
// Handle the authorization callback
router.get('/callback', (req, res) => {
+ console.log('authorization code callback', req.query);
const { code } = req.query;
// Check if the authCode is valid.
@@ -85,13 +95,15 @@ router.get('/callback', (req, res) => {
});
router.post('/token', (req, res) => {
- let grant_type, code, redirect_uri, client_id, client_secret;
+ console.log('authorization code token', req.body, req.headers);
+ let grant_type, code, redirect_uri, client_id, client_secret, code_verifier;
if (req?.body?.grant_type) {
grant_type = req?.body?.grant_type;
code = req?.body?.code;
redirect_uri = req?.body?.redirect_uri;
client_id = req?.body?.client_id;
client_secret = req?.body?.client_secret;
+ code_verifier = req?.body?.code_verifier;
}
if (req?.headers?.grant_type) {
grant_type = req?.headers?.grant_type;
@@ -99,6 +111,7 @@ router.post('/token', (req, res) => {
redirect_uri = req?.headers?.redirect_uri;
client_id = req?.headers?.client_id;
client_secret = req?.headers?.client_secret;
+ code_verifier = req?.headers?.code_verifier;
}
if (grant_type !== 'authorization_code') {
@@ -110,7 +123,13 @@ router.post('/token', (req, res) => {
// return res.status(401).json({ error: 'Invalid client credentials' });
// }
- const storedAuthCode = authCodes.find((t) => t.authCode === code);
+ const storedAuthCode = authCodes.find((t) => {
+ if (!t?.code_challenge) {
+ return t.authCode === code;
+ } else {
+ return t.authCode === code && t.code_challenge === generateCodeChallenge(code_verifier);
+ }
+ });
if (!storedAuthCode) {
return res.status(401).json({ error: 'Invalid Authorization Code' });
@@ -127,6 +146,7 @@ router.post('/token', (req, res) => {
router.post('/resource', (req, res) => {
try {
+ console.log('authorization code resource', req.query, tokens);
const { token } = req.query;
const storedToken = tokens.find((t) => t.accessToken === token);
if (!storedToken) {
diff --git a/packages/bruno-tests/src/auth/oauth2/cc.js b/packages/bruno-tests/src/auth/oauth2/clientCredentials.js
similarity index 77%
rename from packages/bruno-tests/src/auth/oauth2/cc.js
rename to packages/bruno-tests/src/auth/oauth2/clientCredentials.js
index dcaee3027..0c650d51a 100644
--- a/packages/bruno-tests/src/auth/oauth2/cc.js
+++ b/packages/bruno-tests/src/auth/oauth2/clientCredentials.js
@@ -4,7 +4,8 @@ const crypto = require('crypto');
const clients = [
{
client_id: 'client_id_1',
- client_secret: 'client_secret_1'
+ client_secret: 'client_secret_1',
+ scope: 'admin'
}
];
@@ -15,35 +16,39 @@ function generateUniqueString() {
}
router.post('/token', (req, res) => {
- let grant_type, client_id, client_secret;
+ let grant_type, client_id, client_secret, scope;
if (req?.body?.grant_type) {
grant_type = req?.body?.grant_type;
client_id = req?.body?.client_id;
client_secret = req?.body?.client_secret;
+ scope = req?.body?.scope;
} else if (req?.headers?.grant_type) {
grant_type = req?.headers?.grant_type;
client_id = req?.headers?.client_id;
client_secret = req?.headers?.client_secret;
+ scope = req?.headers?.scope;
}
+ console.log('client_cred', client_id, client_secret, scope);
if (grant_type !== 'client_credentials') {
return res.status(401).json({ error: 'Invalid Grant Type, expected "client_credentials"' });
}
- const client = clients.find((c) => c.client_id == client_id && c.client_secret == client_secret);
+ const client = clients.find((c) => c.client_id == client_id && c.client_secret == client_secret && c.scope == scope);
if (!client) {
- return res.status(401).json({ error: 'Invalid client' });
+ return res.status(401).json({ error: 'Invalid client details or scope' });
}
const token = generateUniqueString();
tokens.push({
token,
client_id,
- client_secret
+ client_secret,
+ scope
});
- return res.json({ message: 'Authenticated successfully', access_token: token });
+ return res.json({ message: 'Authenticated successfully', access_token: token, scope });
});
router.get('/resource', (req, res) => {
diff --git a/packages/bruno-tests/src/auth/oauth2/ropc.js b/packages/bruno-tests/src/auth/oauth2/passwordCredentials.js
similarity index 79%
rename from packages/bruno-tests/src/auth/oauth2/ropc.js
rename to packages/bruno-tests/src/auth/oauth2/passwordCredentials.js
index 84bb979a7..2f6760f13 100644
--- a/packages/bruno-tests/src/auth/oauth2/ropc.js
+++ b/packages/bruno-tests/src/auth/oauth2/passwordCredentials.js
@@ -9,23 +9,10 @@ const users = [
}
];
-// P
-// {
-// grant_type: 'password',
-// username: 'foo',
-// password: 'bar'
-// }
-
-// I
-// {
-// grant_type: 'password',
-// username: 'foo',
-// password: 'bar',
-// client_id: 'client_id_1',
-// client_secret: 'client_secret_1'
-// }
router.post('/token', (req, res) => {
- const { grant_type, username, password, client_id, client_secret } = req.body;
+ const { grant_type, username, password, scope } = req.body;
+
+ console.log('password_credentials', username, password, scope);
if (grant_type !== 'password') {
return res.status(401).json({ error: 'Invalid Grant Type' });