Skip to content

Commit

Permalink
feat(#1003): oauth 2.0 client credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
Anoop M D authored and Anoop M D committed Dec 17, 2023
1 parent 454e0e5 commit 5649f7c
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 3 deletions.
Expand Up @@ -71,6 +71,15 @@ const AuthMode = ({ item, collection }) => {
>
Digest Auth
</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onModeChange('oauth2');
}}
>
OAuth
</div>
<div
className="dropdown-item"
onClick={() => {
Expand Down
@@ -0,0 +1,16 @@
import styled from 'styled-components';

const Wrapper = styled.div`
label {
font-size: 0.8125rem;
}
.single-line-editor-wrapper {
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;
78 changes: 78 additions & 0 deletions packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js
@@ -0,0 +1,78 @@
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 OAuth2 = ({ 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: oAuth.grantType,
username: username,
password: oAuth.password
}
})
);
};

const handlePasswordChange = (password) => {
dispatch(
updateAuth({
mode: 'oauth2',
collectionUid: collection.uid,
itemUid: item.uid,
content: {
grantType: oAuth.grantType,
username: oAuth.username,
password: password
}
})
);
};

return (
<StyledWrapper className="mt-2 w-full">
<label className="block font-medium mb-2">Username</label>
<div className="single-line-editor-wrapper mb-2">
<SingleLineEditor
value={oAuth.username || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handleUsernameChange(val)}
onRun={handleRun}
collection={collection}
/>
</div>

<label className="block font-medium mb-2">Password</label>
<div className="single-line-editor-wrapper">
<SingleLineEditor
value={oAuth.password || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handlePasswordChange(val)}
onRun={handleRun}
collection={collection}
/>
</div>
</StyledWrapper>
);
};

export default OAuth2;
6 changes: 6 additions & 0 deletions packages/bruno-app/src/components/RequestPane/Auth/index.js
Expand Up @@ -5,11 +5,14 @@ import AwsV4Auth from './AwsV4Auth';
import BearerAuth from './BearerAuth';
import BasicAuth from './BasicAuth';
import DigestAuth from './DigestAuth';
import OAuth2 from './OAuth2';
import StyledWrapper from './StyledWrapper';

const Auth = ({ item, collection }) => {
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');

console.log(item);

const getAuthView = () => {
switch (authMode) {
case 'awsv4': {
Expand All @@ -24,6 +27,9 @@ const Auth = ({ item, collection }) => {
case 'digest': {
return <DigestAuth collection={collection} item={item} />;
}
case 'oauth2': {
return <OAuth2 collection={collection} item={item} />;
}
}
};

Expand Down
Expand Up @@ -415,6 +415,10 @@ export const collectionsSlice = createSlice({
item.draft.request.auth.mode = 'digest';
item.draft.request.auth.digest = action.payload.content;
break;
case 'oauth2':
item.draft.request.auth.mode = 'oauth2';
item.draft.request.auth.oauth2 = action.payload.content;
break;
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/bruno-app/src/utils/collections/index.js
Expand Up @@ -498,6 +498,10 @@ export const humanizeRequestAuthMode = (mode) => {
label = 'Digest Auth';
break;
}
case 'oauth2': {
label = 'OAuth 2.0';
break;
}
}

return label;
Expand Down
11 changes: 11 additions & 0 deletions packages/bruno-electron/src/ipc/network/prepare-request.js
Expand Up @@ -64,6 +64,17 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
username: get(request, 'auth.digest.username'),
password: get(request, 'auth.digest.password')
};
break;
case 'oauth2':
const grantType = get(request, 'auth.oauth2.grantType');
if (grantType === 'resourceOwnerPasswordCredentials') {
axiosRequest.data = {
grant_type: grantType,
username: get(request, 'auth.oauth2.username'),
password: get(request, 'auth.oauth2.password')
};
}
break;
}
}

Expand Down
18 changes: 17 additions & 1 deletion packages/bruno-lang/v2/src/bruToJson.js
Expand Up @@ -23,7 +23,7 @@ const { outdentString } = require('../../v1/src/utils');
*/
const grammar = ohm.grammar(`Bru {
BruFile = (meta | http | query | headers | auths | bodies | varsandassert | script | tests | docs)*
auths = authawsv4 | authbasic | authbearer | authdigest
auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2
bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
bodyforms = bodyformurlencoded | bodymultipart
Expand Down Expand Up @@ -80,6 +80,7 @@ const grammar = ohm.grammar(`Bru {
authbasic = "auth:basic" dictionary
authbearer = "auth:bearer" dictionary
authdigest = "auth:digest" dictionary
authOAuth2 = "auth:oauth2" dictionary
body = "body" st* "{" nl* textblock tagend
bodyjson = "body:json" st* "{" nl* textblock tagend
Expand Down Expand Up @@ -366,6 +367,21 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}
};
},
authOAuth2(_1, dictionary) {
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
const grantTypeKey = _.find(auth, { name: 'grantType' });
const usernameKey = _.find(auth, { name: 'username' });
const passwordKey = _.find(auth, { name: 'password' });
return {
auth: {
oauth2: {
grantType: grantTypeKey ? grantTypeKey.value : '',
username: usernameKey ? usernameKey.value : '',
password: passwordKey ? passwordKey.value : ''
}
}
};
},
bodyformurlencoded(_1, dictionary) {
return {
body: {
Expand Down
10 changes: 10 additions & 0 deletions packages/bruno-lang/v2/src/jsonToBru.js
Expand Up @@ -87,6 +87,16 @@ const jsonToBru = (json) => {
bru += '\n}\n\n';
}

if (auth && auth.oauth2) {
bru += `auth:oauth2 {
${indentString(`grantType: ${auth.oauth2.grantType}`)}
${indentString(`username: ${auth.oauth2.username}`)}
${indentString(`password: ${auth.oauth2.password}`)}
}
`;
}

if (auth && auth.awsv4) {
bru += `auth:awsv4 {
${indentString(`accessKeyId: ${auth.awsv4.accessKeyId}`)}
Expand Down
6 changes: 6 additions & 0 deletions packages/bruno-lang/v2/tests/fixtures/request.bru
Expand Up @@ -22,6 +22,12 @@ headers {
~transaction-id: {{transactionId}}
}

auth:oauth2 {
grantType: resourceOwnerPasswordCredentials
username: john
password: secret
}

auth:awsv4 {
accessKeyId: A12345678
secretAccessKey: thisisasecret
Expand Down
5 changes: 5 additions & 0 deletions packages/bruno-lang/v2/tests/fixtures/request.json
Expand Up @@ -45,6 +45,11 @@
}
],
"auth": {
"oauth2": {
"grantType": "resourceOwnerPasswordCredentials",
"username": "john",
"password": "secret"
},
"awsv4": {
"accessKeyId": "A12345678",
"secretAccessKey": "thisisasecret",
Expand Down
15 changes: 13 additions & 2 deletions packages/bruno-schema/src/collections/index.js
Expand Up @@ -101,12 +101,23 @@ const authDigestSchema = Yup.object({
.noUnknown(true)
.strict();

const oAuth2Schema = Yup.object({
grantType: Yup.string()
.oneOf(['clientCredentials', 'resourceOwnerPasswordCredentials'])
.required('grantType is required'),
username: Yup.string().nullable(),
password: Yup.string().nullable()
})
.noUnknown(true)
.strict();

const authSchema = Yup.object({
mode: Yup.string().oneOf(['none', 'awsv4', 'basic', 'bearer', 'digest']).required('mode is required'),
mode: Yup.string().oneOf(['none', 'awsv4', 'basic', 'bearer', 'digest', 'oauth2']).required('mode is required'),
awsv4: authAwsV4Schema.nullable(),
basic: authBasicSchema.nullable(),
bearer: authBearerSchema.nullable(),
digest: authDigestSchema.nullable()
digest: authDigestSchema.nullable(),
oauth2: oAuth2Schema.nullable()
})
.noUnknown(true)
.strict();
Expand Down

0 comments on commit 5649f7c

Please sign in to comment.