mirror of
https://github.com/usebruno/bruno.git
synced 2025-01-03 04:29:09 +01:00
feat: OAuth 2.0 Client Credentials as Basic Auth - user interface
This commit is contained in:
parent
0e4a4307ad
commit
1ec999ebdd
@ -6,9 +6,10 @@ import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { inputsConfig } from './inputsConfig';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
|
||||
import { clearOauth2Cache } from 'utils/network/index';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { clearOauth2Cache } from 'utils/network';
|
||||
import toast from 'react-hot-toast';
|
||||
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
|
||||
|
||||
const OAuth2AuthorizationCode = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@ -22,7 +23,17 @@ const OAuth2AuthorizationCode = ({ collection }) => {
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth;
|
||||
const {
|
||||
callbackUrl,
|
||||
authorizationUrl,
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
state,
|
||||
pkce
|
||||
} = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
@ -36,6 +47,7 @@ const OAuth2AuthorizationCode = ({ collection }) => {
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
state,
|
||||
pkce,
|
||||
@ -57,6 +69,7 @@ const OAuth2AuthorizationCode = ({ collection }) => {
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
state,
|
||||
pkce: !Boolean(oAuth?.['pkce'])
|
||||
@ -105,6 +118,7 @@ const OAuth2AuthorizationCode = ({ collection }) => {
|
||||
onChange={handlePKCEToggle}
|
||||
/>
|
||||
</div>
|
||||
<ClientCredentialsMethodSelector collection={collection} oAuth={oAuth} />
|
||||
<div className="flex flex-row gap-4">
|
||||
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
|
||||
Get Access Token
|
||||
|
@ -6,7 +6,8 @@ import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { inputsConfig } from './inputsConfig';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
|
||||
|
||||
const OAuth2ClientCredentials = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@ -20,7 +21,7 @@ const OAuth2ClientCredentials = ({ collection }) => {
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const { accessTokenUrl, clientId, clientSecret, scope } = oAuth;
|
||||
const { accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
@ -32,6 +33,7 @@ const OAuth2ClientCredentials = ({ collection }) => {
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
[key]: value
|
||||
}
|
||||
@ -60,6 +62,7 @@ const OAuth2ClientCredentials = ({ collection }) => {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<ClientCredentialsMethodSelector collection={collection} oAuth={oAuth} />
|
||||
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
|
||||
Get Access Token
|
||||
</button>
|
||||
|
@ -6,7 +6,8 @@ import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { inputsConfig } from './inputsConfig';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
|
||||
|
||||
const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@ -20,7 +21,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth;
|
||||
const { accessTokenUrl, username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
@ -34,6 +35,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
password,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
[key]: value
|
||||
}
|
||||
@ -62,6 +64,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<ClientCredentialsMethodSelector collection={collection} oAuth={oAuth} />
|
||||
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
|
||||
Get Access Token
|
||||
</button>
|
||||
|
@ -7,8 +7,9 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { inputsConfig } from './inputsConfig';
|
||||
import { clearOauth2Cache } from 'utils/network/index';
|
||||
import { clearOauth2Cache } from 'utils/network';
|
||||
import toast from 'react-hot-toast';
|
||||
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
|
||||
|
||||
const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@ -22,7 +23,17 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
|
||||
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
|
||||
|
||||
const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth;
|
||||
const {
|
||||
callbackUrl,
|
||||
authorizationUrl,
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
state,
|
||||
pkce
|
||||
} = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
@ -37,6 +48,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
state,
|
||||
scope,
|
||||
pkce,
|
||||
@ -59,6 +71,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
state,
|
||||
scope,
|
||||
pkce: !Boolean(oAuth?.['pkce'])
|
||||
@ -108,6 +121,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
onChange={handlePKCEToggle}
|
||||
/>
|
||||
</div>
|
||||
<ClientCredentialsMethodSelector item={item} collection={collection} oAuth={oAuth} />
|
||||
<div className="flex flex-row gap-4">
|
||||
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
|
||||
Get Access Token
|
||||
|
@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { inputsConfig } from './inputsConfig';
|
||||
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
|
||||
|
||||
const OAuth2ClientCredentials = ({ item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@ -20,7 +21,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => {
|
||||
|
||||
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
|
||||
|
||||
const { accessTokenUrl, clientId, clientSecret, scope } = oAuth;
|
||||
const { accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
@ -33,6 +34,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => {
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
[key]: value
|
||||
}
|
||||
@ -62,6 +64,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<ClientCredentialsMethodSelector item={item} collection={collection} oAuth={oAuth} />
|
||||
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
|
||||
Get Access Token
|
||||
</button>
|
||||
|
@ -0,0 +1,25 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
font-size: 0.8125rem;
|
||||
|
||||
.client-credentials-secret-mode-selector {
|
||||
padding: 0.5rem 0px;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
|
||||
.client-credentials-secret-label {
|
||||
width: fit-content;
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
justify-content: space-between;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
padding: 0.2rem 0.6rem !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -0,0 +1,82 @@
|
||||
import React, { forwardRef, useEffect, useRef } from 'react';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { IconCaretDown } from '@tabler/icons';
|
||||
import { updateAuth, updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { humanizeOAuth2ClientSecretMethod } from 'utils/collections';
|
||||
|
||||
const ClientCredentialsMethodSelector = ({ item, collection, oAuth }) => {
|
||||
const clientSecretMethods = ['client_credentials_basic', 'client_credentials_post'];
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const dropDownRef = useRef();
|
||||
const onDropdownCreate = (ref) => (dropDownRef.current = ref);
|
||||
|
||||
const Icon = forwardRef((props, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="flex items-center justify-end client-credentials-secret-label select-none">
|
||||
{humanizeOAuth2ClientSecretMethod(oAuth?.clientSecretMethod)}{' '}
|
||||
<IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const onClientSecretMethodChange = (clientSecretMethod) => {
|
||||
if (item) {
|
||||
// Update request level authorization
|
||||
dispatch(
|
||||
updateAuth({
|
||||
mode: 'oauth2',
|
||||
collectionUid: collection.uid,
|
||||
itemUid: item.uid,
|
||||
content: {
|
||||
...oAuth,
|
||||
clientSecretMethod: clientSecretMethod
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Update collection level authorization
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'oauth2',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
...oAuth,
|
||||
clientSecretMethod: clientSecretMethod
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
!oAuth?.clientSecretMethod && onClientSecretMethodChange(clientSecretMethods[0]);
|
||||
}, [oAuth.clientSecretMethod]);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<label className="block font-medium mb-2">Send Client Credentials</label>
|
||||
<div className="inline-flex items-center cursor-pointer client-credentials-secret-mode-selector w-fit">
|
||||
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
|
||||
{clientSecretMethods.map((item, index) => (
|
||||
<div
|
||||
key={item}
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropDownRef.current.hide();
|
||||
onClientSecretMethodChange(item);
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
{humanizeOAuth2ClientSecretMethod(item)}
|
||||
{index === 0 ? ` (Default)` : ``}
|
||||
</div>
|
||||
))}
|
||||
</Dropdown>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
export default ClientCredentialsMethodSelector;
|
@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { inputsConfig } from './inputsConfig';
|
||||
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
|
||||
|
||||
const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@ -20,7 +21,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
|
||||
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
|
||||
|
||||
const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth;
|
||||
const { accessTokenUrl, username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
@ -35,6 +36,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
password,
|
||||
clientId,
|
||||
clientSecret,
|
||||
clientSecretMethod,
|
||||
scope,
|
||||
[key]: value
|
||||
}
|
||||
@ -64,6 +66,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<ClientCredentialsMethodSelector item={item} collection={collection} oAuth={oAuth} />
|
||||
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
|
||||
Get Access Token
|
||||
</button>
|
||||
|
@ -723,6 +723,22 @@ export const humanizeGrantType = (mode) => {
|
||||
return label;
|
||||
};
|
||||
|
||||
export const humanizeOAuth2ClientSecretMethod = (mode) => {
|
||||
let label = 'N/A';
|
||||
switch (mode) {
|
||||
case 'client_credentials_basic': {
|
||||
label = 'As Basic Auth Header';
|
||||
break;
|
||||
}
|
||||
case 'client_credentials_post': {
|
||||
label = 'In Request Body';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
export const refreshUidsInItem = (item) => {
|
||||
item.uid = uuid();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user