diff --git a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/StyledWrapper.js
new file mode 100644
index 000000000..6613dd1f3
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/StyledWrapper.js
@@ -0,0 +1,25 @@
+import styled from 'styled-components';
+
+const Wrapper = styled.div`
+ font-size: 0.8125rem;
+
+ .auth-mode-selector {
+ background: ${(props) => props.theme.requestTabPanel.bodyModeSelect.color};
+ border-radius: 3px;
+
+ .dropdown-item {
+ padding: 0.2rem 0.6rem !important;
+ }
+
+ .label-item {
+ padding: 0.2rem 0.6rem !important;
+ }
+ }
+
+ .caret {
+ color: rgb(140, 140, 140);
+ fill: rgb(140 140 140);
+ }
+`;
+
+export default Wrapper;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js
new file mode 100644
index 000000000..3ad80ce13
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js
@@ -0,0 +1,70 @@
+import React, { useRef, forwardRef } from 'react';
+import get from 'lodash/get';
+import { IconCaretDown } from '@tabler/icons';
+import Dropdown from 'components/Dropdown';
+import { useDispatch } from 'react-redux';
+import { updateRequestAuthMode } from 'providers/ReduxStore/slices/collections';
+import { humanizeRequestAuthMode } from 'utils/collections';
+import StyledWrapper from './StyledWrapper';
+
+const AuthMode = ({ item, collection }) => {
+ const dispatch = useDispatch();
+ const dropdownTippyRef = useRef();
+ const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
+ const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
+
+ const Icon = forwardRef((props, ref) => {
+ return (
+
+ {humanizeRequestAuthMode(authMode)}
+
+ );
+ });
+
+ const onModeChange = (value) => {
+ dispatch(
+ updateRequestAuthMode({
+ itemUid: item.uid,
+ collectionUid: collection.uid,
+ mode: value
+ })
+ );
+ };
+
+ return (
+
+
+
} placement="bottom-end">
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('basic');
+ }}
+ >
+ Basic Auth
+
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('bearer');
+ }}
+ >
+ Bearer Token
+
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('none');
+ }}
+ >
+ No Auth
+
+
+
+
+ );
+};
+export default AuthMode;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/StyledWrapper.js
new file mode 100644
index 000000000..e49220854
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/StyledWrapper.js
@@ -0,0 +1,5 @@
+import styled from 'styled-components';
+
+const Wrapper = styled.div``;
+
+export default Wrapper;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js
new file mode 100644
index 000000000..e2f345d23
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import get from 'lodash/get';
+import { useDispatch } from 'react-redux';
+import { updateRequestBody } from 'providers/ReduxStore/slices/collections';
+import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
+import StyledWrapper from './StyledWrapper';
+
+const RequestBody = ({ item, collection }) => {
+ const dispatch = useDispatch();
+ const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
+
+ const onEdit = (value) => {
+ // dispatch(
+ // updateRequestBody({
+ // content: value,
+ // itemUid: item.uid,
+ // collectionUid: collection.uid
+ // })
+ // );
+ };
+
+ if (authMode === 'basic') {
+ return Basic Auth
;
+ }
+
+ if (authMode === 'bearer') {
+ return Bearer Token
;
+ }
+
+ return No Auth;
+};
+export default RequestBody;
diff --git a/packages/bruno-app/src/components/RequestPane/HttpRequestPane/index.js b/packages/bruno-app/src/components/RequestPane/HttpRequestPane/index.js
index caace776f..652414a62 100644
--- a/packages/bruno-app/src/components/RequestPane/HttpRequestPane/index.js
+++ b/packages/bruno-app/src/components/RequestPane/HttpRequestPane/index.js
@@ -7,6 +7,8 @@ import QueryParams from 'components/RequestPane/QueryParams';
import RequestHeaders from 'components/RequestPane/RequestHeaders';
import RequestBody from 'components/RequestPane/RequestBody';
import RequestBodyMode from 'components/RequestPane/RequestBody/RequestBodyMode';
+import Auth from 'components/RequestPane/Auth';
+import AuthMode from 'components/RequestPane/Auth/AuthMode';
import Vars from 'components/RequestPane/Vars';
import Assertions from 'components/RequestPane/Assertions';
import Script from 'components/RequestPane/Script';
@@ -38,6 +40,9 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
case 'headers': {
return ;
}
+ case 'auth': {
+ return ;
+ }
case 'vars': {
return ;
}
@@ -83,6 +88,9 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
selectTab('headers')}>
Headers
+ selectTab('auth')}>
+ Auth
+
selectTab('vars')}>
Vars
@@ -95,13 +103,16 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
selectTab('tests')}>
Tests
- {/* Moved to post mvp */}
- {/* selectTab('auth')}>Auth
*/}
{focusedTab.requestPaneTab === 'body' ? (
) : null}
+ {focusedTab.requestPaneTab === 'auth' ? (
+
+ ) : null}
{getTabPanel(focusedTab.requestPaneTab)}
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 495989eb1..aca21025a 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -563,6 +563,20 @@ export const collectionsSlice = createSlice({
}
}
},
+ updateRequestAuthMode: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+
+ if (collection && collection.items && collection.items.length) {
+ const item = findItemInCollection(collection, action.payload.itemUid);
+
+ if (item && isItemARequest(item)) {
+ if (!item.draft) {
+ item.draft = cloneDeep(item);
+ }
+ item.draft.request.auth.mode = action.payload.mode;
+ }
+ }
+ },
updateRequestBodyMode: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@@ -1170,6 +1184,7 @@ export const {
addMultipartFormParam,
updateMultipartFormParam,
deleteMultipartFormParam,
+ updateRequestAuthMode,
updateRequestBodyMode,
updateRequestBody,
updateRequestGraphqlQuery,
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index 80fe41dd3..c982f4147 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -445,6 +445,22 @@ export const humanizeRequestBodyMode = (mode) => {
return label;
};
+export const humanizeRequestAuthMode = (mode) => {
+ let label = 'No Auth';
+ switch (mode) {
+ case 'basic': {
+ label = 'Basic Auth';
+ break;
+ }
+ case 'bearer': {
+ label = 'Bearer Token';
+ break;
+ }
+ }
+
+ return label;
+};
+
export const refreshUidsInItem = (item) => {
item.uid = uuid();
diff --git a/packages/bruno-electron/src/bru/index.js b/packages/bruno-electron/src/bru/index.js
index 45b10004f..a28c04a7b 100644
--- a/packages/bruno-electron/src/bru/index.js
+++ b/packages/bruno-electron/src/bru/index.js
@@ -61,6 +61,7 @@ const bruToJson = (bru) => {
url: _.get(json, 'http.url'),
params: _.get(json, 'query', []),
headers: _.get(json, 'headers', []),
+ auth: _.get(json, 'auth', {}),
body: _.get(json, 'body', {}),
script: _.get(json, 'script', {}),
vars: _.get(json, 'vars', {}),
@@ -69,6 +70,7 @@ const bruToJson = (bru) => {
}
};
+ transformedJson.request.auth.mode = _.get(json, 'http.auth', 'none');
transformedJson.request.body.mode = _.get(json, 'http.body', 'none');
return transformedJson;
@@ -104,10 +106,12 @@ const jsonToBru = (json) => {
http: {
method: _.lowerCase(_.get(json, 'request.method')),
url: _.get(json, 'request.url'),
+ auth: _.get(json, 'request.auth.mode', 'none'),
body: _.get(json, 'request.body.mode', 'none')
},
query: _.get(json, 'request.params', []),
headers: _.get(json, 'request.headers', []),
+ auth: _.get(json, 'request.auth', {}),
body: _.get(json, 'request.body', {}),
script: _.get(json, 'request.script', {}),
vars: {
diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js
index 7076175b5..81cd2528b 100644
--- a/packages/bruno-schema/src/collections/index.js
+++ b/packages/bruno-schema/src/collections/index.js
@@ -69,6 +69,27 @@ const requestBodySchema = Yup.object({
.noUnknown(true)
.strict();
+const authBasicSchema = Yup.object({
+ username: Yup.string().nullable(),
+ password: Yup.string().nullable()
+})
+ .noUnknown(true)
+ .strict();
+
+const authBearerSchema = Yup.object({
+ token: Yup.string().nullable()
+})
+ .noUnknown(true)
+ .strict();
+
+const authSchema = Yup.object({
+ mode: Yup.string().oneOf(['none', 'basic', 'bearer']).required('mode is required'),
+ basic: authBasicSchema.nullable(),
+ bearer: authBearerSchema.nullable()
+})
+ .noUnknown(true)
+ .strict();
+
// Right now, the request schema is very tightly coupled with http request
// As we introduce more request types in the future, we will improve the definition to support
// schema structure based on other request type
@@ -77,6 +98,7 @@ const requestSchema = Yup.object({
method: requestMethodSchema,
headers: Yup.array().of(keyValueSchema).required('headers are required'),
params: Yup.array().of(keyValueSchema).required('params are required'),
+ auth: authSchema,
body: requestBodySchema,
script: Yup.object({
req: Yup.string().nullable(),