Skip to content

Commit

Permalink
feat(#1003): collection level oauth2, access_token_url & scope for 'C…
Browse files Browse the repository at this point in the history
…lient Credentials' and 'Password Credentials' grant types (#1691)

* feat(#1003): authorization_code grant type PKCE support, code cleanup..
---------

Co-authored-by: lohit-1 <[email protected]>
  • Loading branch information
lohxt1 and lohit-bruno authored Mar 4, 2024
1 parent 9d3df0a commit 858536e
Show file tree
Hide file tree
Showing 84 changed files with 1,706 additions and 569 deletions.
1 change: 1 addition & 0 deletions packages/bruno-app/src/components/CodeEditor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ if (!SERVER_RENDERED) {
'req.getUrl()',
'req.setUrl(url)',
'req.getMethod()',
'req.getAuthMode()',
'req.setMethod(method)',
'req.getHeader(name)',
'req.getHeaders()',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ const AuthMode = ({ collection }) => {
>
Digest Auth
</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onModeChange('oauth2');
}}
>
Oauth2
</div>
<div
className="dropdown-item"
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
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 { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';

const OAuth2AuthorizationCode = ({ collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();

const oAuth = get(collection, 'root.request.auth.oauth2', {});

const handleRun = async () => {
dispatch(sendCollectionOauth2Request(collection.uid));
};

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

const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, pkce } = oAuth;

const handleChange = (key, value) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'authorization_code',
callbackUrl,
authorizationUrl,
accessTokenUrl,
clientId,
clientSecret,
scope,
pkce,
[key]: value
}
})
);
};

const handlePKCEToggle = (e) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'authorization_code',
callbackUrl,
authorizationUrl,
accessTokenUrl,
clientId,
clientSecret,
scope,
pkce: !Boolean(oAuth?.['pkce'])
}
})
);
};

return (
<StyledWrapper className="mt-2 flex w-full gap-4 flex-col">
{inputsConfig.map((input) => {
const { key, label } = input;
return (
<div className="flex flex-col w-full gap-1" key={`input-${key}`}>
<label className="block font-medium">{label}</label>
<div className="single-line-editor-wrapper">
<SingleLineEditor
value={oAuth[key] || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handleChange(key, val)}
onRun={handleRun}
collection={collection}
/>
</div>
</div>
);
})}
<div className="flex flex-row w-full gap-4" key="pkce">
<label className="block font-medium">Use PKCE</label>
<input
className="cursor-pointer"
type="checkbox"
checked={Boolean(oAuth?.['pkce'])}
onChange={handlePKCEToggle}
/>
</div>
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
Get Access Token
</button>
</StyledWrapper>
);
};

export default OAuth2AuthorizationCode;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const inputsConfig = [
{
key: 'callbackUrl',
label: 'Callback URL'
},
{
key: 'authorizationUrl',
label: 'Authorization URL'
},
{
key: 'accessTokenUrl',
label: 'Access Token URL'
},
{
key: 'clientId',
label: 'Client ID'
},
{
key: 'clientSecret',
label: 'Client Secret'
},
{
key: 'scope',
label: 'Scope'
}
];

export { inputsConfig };
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import styled from 'styled-components';

const Wrapper = styled.div`
label {
font-size: 0.8125rem;
}
.single-line-editor-wrapper {
max-width: 400px;
padding: 0.15rem 0.4rem;
border-radius: 3px;
border: solid 1px ${(props) => props.theme.input.border};
background-color: ${(props) => props.theme.input.bg};
}
`;

export default Wrapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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 { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';

const OAuth2ClientCredentials = ({ collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();

const oAuth = get(collection, 'root.request.auth.oauth2', {});

const handleRun = async () => {
dispatch(sendCollectionOauth2Request(collection.uid));
};

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

const { accessTokenUrl, clientId, clientSecret, scope } = oAuth;

const handleChange = (key, value) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'client_credentials',
accessTokenUrl,
clientId,
clientSecret,
scope,
[key]: value
}
})
);
};

return (
<StyledWrapper className="mt-2 flex w-full gap-4 flex-col">
{inputsConfig.map((input) => {
const { key, label } = input;
return (
<div className="flex flex-col w-full gap-1" key={`input-${key}`}>
<label className="block font-medium">{label}</label>
<div className="single-line-editor-wrapper">
<SingleLineEditor
value={oAuth[key] || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handleChange(key, val)}
onRun={handleRun}
collection={collection}
/>
</div>
</div>
);
})}
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
Get Access Token
</button>
</StyledWrapper>
);
};

export default OAuth2ClientCredentials;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const inputsConfig = [
{
key: 'accessTokenUrl',
label: 'Access Token URL'
},
{
key: 'clientId',
label: 'Client ID'
},
{
key: 'clientSecret',
label: 'Client Secret'
},
{
key: 'scope',
label: 'Scope'
}
];

export { inputsConfig };
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import styled from 'styled-components';

const Wrapper = styled.div`
font-size: 0.8125rem;
.grant-type-mode-selector {
padding: 0.5rem 0px;
border-radius: 3px;
border: solid 1px ${(props) => props.theme.input.border};
background-color: ${(props) => props.theme.input.bg};
.dropdown {
width: fit-content;
div[data-tippy-root] {
width: fit-content;
}
.tippy-box {
width: fit-content;
max-width: none !important;
.tippy-content: {
width: fit-content;
max-width: none !important;
}
}
}
.grant-type-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;
}
.label-item {
padding: 0.2rem 0.6rem !important;
}
}
.caret {
color: rgb(140, 140, 140);
fill: rgb(140 140 140);
}
label {
font-size: 0.8125rem;
}
`;

export default Wrapper;
Loading

0 comments on commit 858536e

Please sign in to comment.