Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: OAuth2: Show details of both token request and user request in the Timeline #2253

Draft
wants to merge 1 commit into
base: fix/oauth2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions packages/bruno-app/src/components/ResponsePane/Timeline/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import StyledWrapper from './StyledWrapper';
const Timeline = ({ request, response }) => {
const requestHeaders = [];
const responseHeaders = typeof response.headers === 'object' ? Object.entries(response.headers) : [];
const requestData = typeof request?.data === "string" ? request?.data : safeStringifyJSON(request?.data, true);

const authRequest = request.authRequest;
const authResponse = request.authResponse;
const authRequestHeaders = typeof authRequest?.headers === 'object' ? Object.entries(authRequest.headers) : [];
const authResponseHeaders = typeof authResponse?.headers === 'object' ? Object.entries(authResponse?.headers) : [];
const authRequestData = authRequest?.data === "string" ? authRequest?.data : safeStringifyJSON(authRequest?.data, true);

request = request || {};
response = response || {};
Expand All @@ -17,10 +24,45 @@ const Timeline = ({ request, response }) => {
});
});

let requestData = typeof request?.data === "string" ? request?.data : safeStringifyJSON(request?.data, true);

return (
<StyledWrapper className="pb-4 w-full">
{authRequest ? (
<>
<div>
<pre className="line request font-bold">
<span className="arrow">{'>'}</span> {authRequest.method} {authRequest.url}
</pre>
{authRequestHeaders.map((h) => {
return (
<pre className="line request" key={h[0]}>
<span className="arrow">{'>'}</span> {h[0]}: {h[1]}
</pre>
);
})}
{authRequestData ? (
<pre className="line request">
<span className="arrow">{'>'}</span> data {authRequestData}
</pre>
) : null}
</div>
{authResponse ? (
<div className="mt-4">
<pre className="line response font-bold">
<span className="arrow">{'<'}</span> {authResponse.status} {authResponse.statusText}
</pre>
{authResponseHeaders.map((h) => {
return (
<pre className="line response" key={h[0]}>
<span className="arrow">{'<'}</span> {h[0]}: {h[1]}
</pre>
);
})}
</div>
) : null}
<div className="mt-4" />
</>
) : null}

<div>
<pre className="line request font-bold">
<span className="arrow">{'>'}</span> {request.method} {request.url}
Expand Down
42 changes: 35 additions & 7 deletions packages/bruno-electron/src/ipc/network/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,23 +276,33 @@ const configureRequest = async (
if (request.oauth2) {
let requestCopy = cloneDeep(request);
interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars);
let credentials, response;
let credentials, authResponse, authRequest;
switch (request?.oauth2?.grantType) {
case 'authorization_code': {
({ credentials, response } = await oauth2AuthorizeWithAuthorizationCode(requestCopy, collectionUid));
({ credentials, authRequest, authResponse } = await oauth2AuthorizeWithAuthorizationCode(
requestCopy,
collectionUid
));
break;
}
case 'client_credentials': {
({ credentials, response } = await oauth2AuthorizeWithClientCredentials(requestCopy, collectionUid));
({ credentials, authRequest, authResponse } = await oauth2AuthorizeWithClientCredentials(
requestCopy,
collectionUid
));
break;
}
case 'password': {
({ credentials, response } = await oauth2AuthorizeWithPasswordCredentials(requestCopy, collectionUid));
({ credentials, authRequest, authResponse } = await oauth2AuthorizeWithPasswordCredentials(
requestCopy,
collectionUid
));
break;
}
}
request.credentials = credentials;
request.authRequestResponse = response;
request.authRequest = authRequest;
request.authResponse = authResponse;

// Bruno can handle bearer token type automatically.
// Other - more exotic token types are not touched
Expand Down Expand Up @@ -598,6 +608,24 @@ const registerNetworkIpc = (mainWindow) => {
method: request.method,
headers: request.headers,
data: safeParseJSON(safeStringifyJSON(request.data)),
authRequest: request.authRequest
? {
url: request.authRequest.url,
method: request.authRequest.method,
headers: request.authRequest.headers,
data: request.authRequest.data,
timestamp: request.authRequest.timestamp
}
: null,
authResponse: request.authResponse
? {
headers: request.authResponse ? request.authResponse.headers : [],
data: request.authResponse.data ? parseDataFromResponse(request.authResponse).data : {},
status: request.authResponse.status,
statusText: request.authResponse.statusText,
timestamp: request.authResponse.timestamp
}
: null,
timestamp: Date.now()
},
collectionUid,
Expand Down Expand Up @@ -784,8 +812,8 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);

const response = request.authRequestResponse;
// When credentials are loaded from cache, authRequestResponse has no data
const response = request.authResponse;
// When credentials are loaded from cache, authResponse has no data
if (response.data) {
const { data } = parseDataFromResponse(response, request.__brunoDisableParsingResponseJson);
response.data = data;
Expand Down
25 changes: 13 additions & 12 deletions packages/bruno-electron/src/ipc/network/oauth2-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const oauth2AuthorizeWithAuthorizationCode = async (request, collectionUid) => {
const { cachedCredentials } = getPersistedOauth2Credentials(collectionUid);
if (cachedCredentials?.access_token) {
console.log('Reusing Stored access token');
return { credentials: cachedCredentials, response: {} };
return { credentials: cachedCredentials, authRequest: null, authResponse: null };
}

let codeVerifier = generateCodeVerifier();
Expand All @@ -62,10 +62,11 @@ const oauth2AuthorizeWithAuthorizationCode = async (request, collectionUid) => {
request.url = request?.oauth2?.accessTokenUrl;

const axiosInstance = makeAxiosInstance();
const response = await axiosInstance(request);
const credentials = JSON.parse(response.data);
const authResponse = await axiosInstance(request);
const credentials = JSON.parse(authResponse.data);
persistOauth2Credentials(credentials, collectionUid);
return { credentials, response };

return { credentials, authRequest: request, authResponse };
};

const getOAuth2AuthorizationCode = (request, codeChallenge, collectionUid) => {
Expand Down Expand Up @@ -108,7 +109,7 @@ const oauth2AuthorizeWithClientCredentials = async (request, collectionUid) => {
const { cachedCredentials } = getPersistedOauth2Credentials(collectionUid);
if (cachedCredentials?.access_token) {
console.log('Reusing Stored access token');
return { credentials: cachedCredentials, response: {} };
return { credentials: cachedCredentials, authRequest: null, authResponse: null };
}

let requestCopy = cloneDeep(request);
Expand All @@ -129,10 +130,10 @@ const oauth2AuthorizeWithClientCredentials = async (request, collectionUid) => {
request.url = request?.oauth2?.accessTokenUrl;

const axiosInstance = makeAxiosInstance();
let response = await axiosInstance(request);
let credentials = JSON.parse(response.data);
let authResponse = await axiosInstance(request);
let credentials = JSON.parse(authResponse.data);
persistOauth2Credentials(credentials, collectionUid);
return { credentials, response };
return { credentials, authRequest: request, authResponse };
};

// PASSWORD CREDENTIALS
Expand All @@ -141,7 +142,7 @@ const oauth2AuthorizeWithPasswordCredentials = async (request, collectionUid) =>
const { cachedCredentials } = getPersistedOauth2Credentials(collectionUid);
if (cachedCredentials?.access_token) {
console.log('Reusing Stored access token');
return { credentials: cachedCredentials, response: {} };
return { credentials: cachedCredentials, authRequest: null, authResponse: null };
}

const oAuth = get(request, 'oauth2', {});
Expand All @@ -163,10 +164,10 @@ const oauth2AuthorizeWithPasswordCredentials = async (request, collectionUid) =>
request.url = request?.oauth2?.accessTokenUrl;

const axiosInstance = makeAxiosInstance();
let response = await axiosInstance(request);
let credentials = JSON.parse(response.data);
let authResponse = await axiosInstance(request);
let credentials = JSON.parse(authResponse.data);
persistOauth2Credentials(credentials, collectionUid);
return { credentials, response };
return { credentials, authRequest: request, authResponse };
};
module.exports = {
oauth2AuthorizeWithAuthorizationCode,
Expand Down
Loading