Skip to content

Commit 041cbf2

Browse files
committed
feat: OAuth 2.0 Client Credentials as Basic Auth - user interface
#2106
1 parent d4e91a8 commit 041cbf2

File tree

9 files changed

+172
-9
lines changed

9 files changed

+172
-9
lines changed

packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/AuthorizationCode/index.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import SingleLineEditor from 'components/SingleLineEditor';
66
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
77
import StyledWrapper from './StyledWrapper';
88
import { inputsConfig } from './inputsConfig';
9-
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
10-
import { clearOauth2Cache } from 'utils/network/index';
9+
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
10+
import { clearOauth2Cache } from 'utils/network';
1111
import toast from 'react-hot-toast';
12+
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
1213

1314
const OAuth2AuthorizationCode = ({ collection }) => {
1415
const dispatch = useDispatch();
@@ -22,7 +23,17 @@ const OAuth2AuthorizationCode = ({ collection }) => {
2223

2324
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
2425

25-
const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth;
26+
const {
27+
callbackUrl,
28+
authorizationUrl,
29+
accessTokenUrl,
30+
clientId,
31+
clientSecret,
32+
clientSecretMethod,
33+
scope,
34+
state,
35+
pkce
36+
} = oAuth;
2637

2738
const handleChange = (key, value) => {
2839
dispatch(
@@ -36,6 +47,7 @@ const OAuth2AuthorizationCode = ({ collection }) => {
3647
accessTokenUrl,
3748
clientId,
3849
clientSecret,
50+
clientSecretMethod,
3951
scope,
4052
state,
4153
pkce,
@@ -57,6 +69,7 @@ const OAuth2AuthorizationCode = ({ collection }) => {
5769
accessTokenUrl,
5870
clientId,
5971
clientSecret,
72+
clientSecretMethod,
6073
scope,
6174
state,
6275
pkce: !Boolean(oAuth?.['pkce'])
@@ -104,6 +117,7 @@ const OAuth2AuthorizationCode = ({ collection }) => {
104117
onChange={handlePKCEToggle}
105118
/>
106119
</div>
120+
<ClientCredentialsMethodSelector collection={collection} oAuth={oAuth} />
107121
<div className="flex flex-row gap-4">
108122
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
109123
Get Access Token

packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/ClientCredentials/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/Redux
77
import StyledWrapper from './StyledWrapper';
88
import { inputsConfig } from './inputsConfig';
99
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
10+
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
1011

1112
const OAuth2ClientCredentials = ({ collection }) => {
1213
const dispatch = useDispatch();
@@ -20,7 +21,7 @@ const OAuth2ClientCredentials = ({ collection }) => {
2021

2122
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
2223

23-
const { accessTokenUrl, clientId, clientSecret, scope } = oAuth;
24+
const { accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
2425

2526
const handleChange = (key, value) => {
2627
dispatch(
@@ -32,6 +33,7 @@ const OAuth2ClientCredentials = ({ collection }) => {
3233
accessTokenUrl,
3334
clientId,
3435
clientSecret,
36+
clientSecretMethod,
3537
scope,
3638
[key]: value
3739
}
@@ -59,6 +61,7 @@ const OAuth2ClientCredentials = ({ collection }) => {
5961
</div>
6062
);
6163
})}
64+
<ClientCredentialsMethodSelector collection={collection} oAuth={oAuth} />
6265
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
6366
Get Access Token
6467
</button>

packages/bruno-app/src/components/CollectionSettings/Auth/OAuth2/PasswordCredentials/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/Redux
77
import StyledWrapper from './StyledWrapper';
88
import { inputsConfig } from './inputsConfig';
99
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
10+
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
1011

1112
const OAuth2AuthorizationCode = ({ item, collection }) => {
1213
const dispatch = useDispatch();
@@ -20,7 +21,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
2021

2122
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
2223

23-
const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth;
24+
const { accessTokenUrl, username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
2425

2526
const handleChange = (key, value) => {
2627
dispatch(
@@ -34,6 +35,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
3435
password,
3536
clientId,
3637
clientSecret,
38+
clientSecretMethod,
3739
scope,
3840
[key]: value
3941
}
@@ -61,6 +63,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
6163
</div>
6264
);
6365
})}
66+
<ClientCredentialsMethodSelector collection={collection} oAuth={oAuth} />
6467
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
6568
Get Access Token
6669
</button>

packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections';
77
import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
88
import StyledWrapper from './StyledWrapper';
99
import { inputsConfig } from './inputsConfig';
10-
import { clearOauth2Cache } from 'utils/network/index';
10+
import { clearOauth2Cache } from 'utils/network';
1111
import toast from 'react-hot-toast';
12+
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
1213

1314
const OAuth2AuthorizationCode = ({ item, collection }) => {
1415
const dispatch = useDispatch();
@@ -22,7 +23,17 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
2223

2324
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
2425

25-
const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth;
26+
const {
27+
callbackUrl,
28+
authorizationUrl,
29+
accessTokenUrl,
30+
clientId,
31+
clientSecret,
32+
clientSecretMethod,
33+
scope,
34+
state,
35+
pkce
36+
} = oAuth;
2637

2738
const handleChange = (key, value) => {
2839
dispatch(
@@ -37,6 +48,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
3748
accessTokenUrl,
3849
clientId,
3950
clientSecret,
51+
clientSecretMethod,
4052
state,
4153
scope,
4254
pkce,
@@ -59,6 +71,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
5971
accessTokenUrl,
6072
clientId,
6173
clientSecret,
74+
clientSecretMethod,
6275
state,
6376
scope,
6477
pkce: !Boolean(oAuth?.['pkce'])
@@ -106,6 +119,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
106119
onChange={handlePKCEToggle}
107120
/>
108121
</div>
122+
<ClientCredentialsMethodSelector item={item} collection={collection} oAuth={oAuth} />
109123
<div className="flex flex-row gap-4">
110124
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
111125
Get Access Token

packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections';
77
import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
88
import StyledWrapper from './StyledWrapper';
99
import { inputsConfig } from './inputsConfig';
10+
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
1011

1112
const OAuth2ClientCredentials = ({ item, collection }) => {
1213
const dispatch = useDispatch();
@@ -20,7 +21,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => {
2021

2122
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
2223

23-
const { accessTokenUrl, clientId, clientSecret, scope } = oAuth;
24+
const { accessTokenUrl, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
2425

2526
const handleChange = (key, value) => {
2627
dispatch(
@@ -33,6 +34,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => {
3334
accessTokenUrl,
3435
clientId,
3536
clientSecret,
37+
clientSecretMethod,
3638
scope,
3739
[key]: value
3840
}
@@ -60,6 +62,7 @@ const OAuth2ClientCredentials = ({ item, collection }) => {
6062
</div>
6163
);
6264
})}
65+
<ClientCredentialsMethodSelector item={item} collection={collection} oAuth={oAuth} />
6366
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
6467
Get Access Token
6568
</button>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import styled from 'styled-components';
2+
3+
const Wrapper = styled.div`
4+
font-size: 0.8125rem;
5+
6+
.client-credentials-secret-mode-selector {
7+
padding: 0.5rem 0px;
8+
border-radius: 3px;
9+
border: solid 1px ${(props) => props.theme.input.border};
10+
background-color: ${(props) => props.theme.input.bg};
11+
12+
.client-credentials-secret-label {
13+
width: fit-content;
14+
color: ${(props) => props.theme.colors.text.yellow};
15+
justify-content: space-between;
16+
padding: 0 0.5rem;
17+
}
18+
19+
.dropdown-item {
20+
padding: 0.2rem 0.6rem !important;
21+
}
22+
}
23+
`;
24+
25+
export default Wrapper;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React, { forwardRef, useEffect, useRef } from 'react';
2+
import Dropdown from 'components/Dropdown';
3+
import StyledWrapper from './StyledWrapper';
4+
import { IconCaretDown } from '@tabler/icons';
5+
import { updateAuth, updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
6+
import { useDispatch } from 'react-redux';
7+
import { humanizeOAuth2ClientSecretMethod } from 'utils/collections';
8+
9+
const ClientCredentialsMethodSelector = ({ item, collection, oAuth }) => {
10+
const clientSecretMethods = ['client_credentials_basic', 'client_credentials_post'];
11+
12+
const dispatch = useDispatch();
13+
const dropDownRef = useRef();
14+
const onDropdownCreate = (ref) => (dropDownRef.current = ref);
15+
16+
const Icon = forwardRef((props, ref) => {
17+
return (
18+
<div ref={ref} className="flex items-center justify-end client-credentials-secret-label select-none">
19+
{humanizeOAuth2ClientSecretMethod(oAuth?.clientSecretMethod)}{' '}
20+
<IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
21+
</div>
22+
);
23+
});
24+
25+
const onClientSecretMethodChange = (clientSecretMethod) => {
26+
if (item) {
27+
// Update request level authentication
28+
dispatch(
29+
updateAuth({
30+
mode: 'oauth2',
31+
collectionUid: collection.uid,
32+
itemUid: item.uid,
33+
content: {
34+
...oAuth,
35+
clientSecretMethod: clientSecretMethod
36+
}
37+
})
38+
);
39+
} else {
40+
// Update collection level authentication
41+
dispatch(
42+
updateCollectionAuth({
43+
mode: 'oauth2',
44+
collectionUid: collection.uid,
45+
content: {
46+
...oAuth,
47+
clientSecretMethod: clientSecretMethod
48+
}
49+
})
50+
);
51+
}
52+
};
53+
54+
useEffect(() => {
55+
!oAuth?.clientSecretMethod && onClientSecretMethodChange(clientSecretMethods[0]);
56+
}, [oAuth.clientSecretMethod]);
57+
58+
return (
59+
<StyledWrapper>
60+
<label className="block font-medium mb-2">Send Client Credentials</label>
61+
<div className="inline-flex items-center cursor-pointer client-credentials-secret-mode-selector w-fit">
62+
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
63+
{clientSecretMethods.map((item, index) => (
64+
<div
65+
key={item}
66+
className="dropdown-item"
67+
onClick={() => {
68+
dropDownRef.current.hide();
69+
onClientSecretMethodChange(item);
70+
}}
71+
>
72+
{' '}
73+
{humanizeOAuth2ClientSecretMethod(item)}
74+
{index === 0 ? ` (Default)` : ``}
75+
</div>
76+
))}
77+
</Dropdown>
78+
</div>
79+
</StyledWrapper>
80+
);
81+
};
82+
export default ClientCredentialsMethodSelector;

packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections';
77
import { saveRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions';
88
import StyledWrapper from './StyledWrapper';
99
import { inputsConfig } from './inputsConfig';
10+
import ClientCredentialsMethodSelector from 'components/RequestPane/Auth/OAuth2/ClientCredentialsMethodSelector';
1011

1112
const OAuth2AuthorizationCode = ({ item, collection }) => {
1213
const dispatch = useDispatch();
@@ -20,7 +21,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
2021

2122
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
2223

23-
const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth;
24+
const { accessTokenUrl, username, password, clientId, clientSecret, clientSecretMethod, scope } = oAuth;
2425

2526
const handleChange = (key, value) => {
2627
dispatch(
@@ -35,6 +36,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
3536
password,
3637
clientId,
3738
clientSecret,
39+
clientSecretMethod,
3840
scope,
3941
[key]: value
4042
}
@@ -62,6 +64,7 @@ const OAuth2AuthorizationCode = ({ item, collection }) => {
6264
</div>
6365
);
6466
})}
67+
<ClientCredentialsMethodSelector item={item} collection={collection} oAuth={oAuth} />
6568
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
6669
Get Access Token
6770
</button>

packages/bruno-app/src/utils/collections/index.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,22 @@ export const humanizeGrantType = (mode) => {
582582
return label;
583583
};
584584

585+
export const humanizeOAuth2ClientSecretMethod = (mode) => {
586+
let label = 'N/A';
587+
switch (mode) {
588+
case 'client_credentials_basic': {
589+
label = 'As Basic Auth Header';
590+
break;
591+
}
592+
case 'client_credentials_post': {
593+
label = 'In Request Body';
594+
break;
595+
}
596+
}
597+
598+
return label;
599+
};
600+
585601
export const refreshUidsInItem = (item) => {
586602
item.uid = uuid();
587603

0 commit comments

Comments
 (0)