From 8e873013a9e69855ed21b64cd8e033173229fb69 Mon Sep 17 00:00:00 2001 From: lohxt1 Date: Tue, 25 Mar 2025 15:42:58 +0530 Subject: [PATCH] oauth2 fixes --- .../Auth/OAuth2/AuthorizationCode/index.js | 94 +-------------- .../Auth/OAuth2/ClientCredentials/index.js | 75 +----------- .../Auth/OAuth2/Oauth2ActionButtons/index.js | 96 +++++++++++++++ .../Auth/OAuth2/Oauth2TokenViewer/index.js | 42 ++++--- .../Auth/OAuth2/PasswordCredentials/index.js | 75 +----------- .../ReduxStore/slices/collections/actions.js | 4 +- .../ReduxStore/slices/collections/index.js | 3 - packages/bruno-electron/src/ipc/collection.js | 4 +- packages/bruno-electron/src/utils/oauth2.js | 109 +++++++++++++++++- 9 files changed, 239 insertions(+), 263 deletions(-) create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js index 40f74c713..c00964d82 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js @@ -1,28 +1,20 @@ -import React, { useRef, forwardRef, useState, useEffect, useMemo } from 'react'; +import React, { useRef, forwardRef } from 'react'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; -import { IconCaretDown, IconLoader2, IconSettings, IconKey, IconHelp, IconAdjustmentsHorizontal } from '@tabler/icons'; +import { IconCaretDown, IconSettings, IconKey, IconHelp, IconAdjustmentsHorizontal } from '@tabler/icons'; import Dropdown from 'components/Dropdown'; import SingleLineEditor from 'components/SingleLineEditor'; -import { clearOauth2Cache, fetchOauth2Credentials, refreshOauth2Credentials } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; -import toast from 'react-hot-toast'; import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; -import { cloneDeep, find } from 'lodash'; -import { getAllVariables } from 'utils/collections/index'; -import brunoCommon from '@usebruno/common'; -const { interpolate } = brunoCommon; +import Oauth2ActionButtons from '../Oauth2ActionButtons/index'; const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAuth, collection, folder }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); const dropdownTippyRef = useRef(); const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - const [fetchingToken, toggleFetchingToken] = useState(false); - const [refreshingToken, toggleRefreshingToken] = useState(false); - const [showRefreshButton, setShowRefreshButton] = useState(false); const oAuth = get(request, 'auth.oauth2', {}); const { @@ -44,17 +36,9 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu autoFetchToken } = oAuth; - const { uid: collectionUid } = collection; - - const interpolatedAccessTokenUrl = useMemo(() => { - const variables = getAllVariables(collection, item); - return interpolate(accessTokenUrl, variables); - }, [collection, item, accessTokenUrl]); - const refreshTokenUrlAvailable = refreshTokenUrl?.trim() !== ''; const isAutoRefreshDisabled = !refreshTokenUrlAvailable; - const TokenPlacementIcon = forwardRef((props, ref) => { return (
@@ -73,46 +57,6 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu ); }); - - const handleFetchOauth2Credentials = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleFetchingToken(true); - try { - await dispatch(fetchOauth2Credentials({ - itemUid: item.uid, - request: requestCopy, - collection, - folderUid: folder?.uid || null - })); - toggleFetchingToken(false); - toast.success('token fetched successfully!'); - } - catch (error) { - console.error(error); - toggleFetchingToken(false); - toast.error('An error occured while fetching token!'); - } - } - - const handleRefreshAccessToken = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleRefreshingToken(true); - try { - await dispatch(refreshOauth2Credentials({ request: requestCopy, collection })); - toggleRefreshingToken(false); - toast.success('token refreshed successfully!'); - } - catch (error) { - console.error(error); - toggleRefreshingToken(false); - toast.error('An error occured while refreshing token!'); - } - } - const handleSave = () => { save(); }; const handleChange = (key, value) => { @@ -172,24 +116,6 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu ); }; - const handleClearCache = (e) => { - dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: interpolatedAccessTokenUrl, credentialsId })) - .then(() => { - toast.success('cleared cache successfully'); - }) - .catch((err) => { - toast.error(err.message); - }); - }; - - const credentialsData = find(collection?.oauth2Credentials, creds => creds?.url == interpolatedAccessTokenUrl && creds?.collectionUid == collectionUid && creds?.credentialsId == credentialsId); - const creds = credentialsData?.credentials || {}; - - useEffect(() => { - // Update visibility whenever credentials change - setShowRefreshButton(Boolean(creds?.refresh_token && creds?.access_token)); - }, [creds?.refresh_token, creds?.access_token, credentialsData]); - return ( @@ -400,19 +326,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu
-
- - {showRefreshButton && ( - - )} - -
+ ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js index 72548d6a0..98b3e4607 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js @@ -1,27 +1,20 @@ -import React, { useRef, forwardRef, useState, useMemo } from 'react'; +import React, { useRef, forwardRef } from 'react'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; -import { IconCaretDown, IconLoader2, IconSettings, IconKey, IconAdjustmentsHorizontal, IconHelp } from '@tabler/icons'; +import { IconCaretDown, IconSettings, IconKey, IconAdjustmentsHorizontal, IconHelp } from '@tabler/icons'; import SingleLineEditor from 'components/SingleLineEditor'; -import { fetchOauth2Credentials, clearOauth2Cache, refreshOauth2Credentials } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; import Dropdown from 'components/Dropdown'; import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; -import toast from 'react-hot-toast'; -import { cloneDeep } from 'lodash'; -import { getAllVariables } from 'utils/collections/index'; -import brunoCommon from '@usebruno/common'; -const { interpolate } = brunoCommon; +import Oauth2ActionButtons from '../Oauth2ActionButtons/index'; const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAuth, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); const dropdownTippyRef = useRef(); const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - const [fetchingToken, toggleFetchingToken] = useState(false); - const [refreshingToken, toggleRefreshingToken] = useState(false); const oAuth = get(request, 'auth.oauth2', {}); @@ -40,48 +33,9 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu autoFetchToken } = oAuth; - const interpolatedAccessTokenUrl = useMemo(() => { - const variables = getAllVariables(collection, item); - return interpolate(accessTokenUrl, variables); - }, [collection, item, accessTokenUrl]); - const refreshTokenUrlAvailable = refreshTokenUrl?.trim() !== ''; const isAutoRefreshDisabled = !refreshTokenUrlAvailable; - const handleFetchOauth2Credentials = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleFetchingToken(true); - try { - await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); - toggleFetchingToken(false); - toast.success('Token fetched successfully!'); - } - catch (error) { - console.error('could not fetch the token!'); - console.error(error); - toggleFetchingToken(false); - toast.error('An error occured while fetching token!'); - } - } - - const handleRefreshAccessToken = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleRefreshingToken(true); - try { - await dispatch(refreshOauth2Credentials({ request: requestCopy, collection })); - toggleRefreshingToken(false); - toast.success('token refreshed successfully!'); - } - catch(error) { - console.error(error); - toggleRefreshingToken(false); - toast.error('An error occured while refreshing token!'); - } - }; const handleSave = () => { save(); }; @@ -129,16 +83,6 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu ); }; - const handleClearCache = (e) => { - dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: interpolatedAccessTokenUrl, credentialsId })) - .then(() => { - toast.success('cleared cache successfully'); - }) - .catch((err) => { - toast.error(err.message); - }); - }; - return ( @@ -352,17 +296,8 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu -
- - - -
+ +
); }; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js new file mode 100644 index 000000000..73b5de060 --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2ActionButtons/index.js @@ -0,0 +1,96 @@ +import { useMemo, useState } from "react"; +import { useDispatch } from "react-redux"; +import toast from 'react-hot-toast'; +import { cloneDeep, find } from 'lodash'; +import { IconLoader2 } from '@tabler/icons'; +import brunoCommon from '@usebruno/common'; +const { interpolate } = brunoCommon; +import { fetchOauth2Credentials, clearOauth2Cache, refreshOauth2Credentials } from 'providers/ReduxStore/slices/collections/actions'; +import { getAllVariables } from "utils/collections/index"; + +const Oauth2ActionButtons = ({ item, request, collection, url: accessTokenUrl, credentialsId }) => { + const { uid: collectionUid } = collection; + + const dispatch = useDispatch(); + const [fetchingToken, toggleFetchingToken] = useState(false); + const [refreshingToken, toggleRefreshingToken] = useState(false); + + const interpolatedAccessTokenUrl = useMemo(() => { + const variables = getAllVariables(collection, item); + return interpolate(accessTokenUrl, variables); + }, [collection, item, accessTokenUrl]); + + const credentialsData = find(collection?.oauth2Credentials, creds => creds?.url == interpolatedAccessTokenUrl && creds?.collectionUid == collectionUid && creds?.credentialsId == credentialsId); + const creds = credentialsData?.credentials || {}; + + const handleFetchOauth2Credentials = async () => { + let requestCopy = cloneDeep(request); + requestCopy.oauth2 = requestCopy?.auth.oauth2; + requestCopy.headers = {}; + toggleFetchingToken(true); + try { + const credentials = await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); + toggleFetchingToken(false); + if (credentials?.access_token) { + toast.success('token fetched successfully!'); + } + else { + toast.error('An error occured while fetching token!'); + } + } + catch (error) { + console.error('could not fetch the token!'); + console.error(error); + toggleFetchingToken(false); + toast.error('An error occured while fetching token!'); + } + } + + const handleRefreshAccessToken = async () => { + let requestCopy = cloneDeep(request); + requestCopy.oauth2 = requestCopy?.auth.oauth2; + requestCopy.headers = {}; + toggleRefreshingToken(true); + try { + const credentials = await dispatch(refreshOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); + toggleRefreshingToken(false); + if (credentials?.access_token) { + toast.success('token refreshed successfully!'); + } + else { + toast.error('An error occured while refreshing token!'); + } + } + catch(error) { + console.error(error); + toggleRefreshingToken(false); + toast.error('An error occured while refreshing token!'); + } + }; + + const handleClearCache = (e) => { + dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: interpolatedAccessTokenUrl, credentialsId })) + .then(() => { + toast.success('cleared cache successfully'); + }) + .catch((err) => { + toast.error(err.message); + }); + }; + + return ( +
+ + {creds?.refresh_token ? : null} + +
+ ) +} + +export default Oauth2ActionButtons; \ No newline at end of file diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2TokenViewer/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2TokenViewer/index.js index 7a95fa1f8..13168b082 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2TokenViewer/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Oauth2TokenViewer/index.js @@ -140,25 +140,29 @@ const Oauth2TokenViewer = ({ collection, item, url, credentialsId, handleRun }) return ( {Object.keys(creds)?.length ? ( -
- - - - {(creds.token_type || creds.scope) ?
-
- {creds.token_type ?
- Token Type: - {creds.token_type} -
: null} - {creds?.scope ?
- Scope: - - {creds.scope} - -
: null} -
-
: null} -
+ creds?.error ? ( +
Error fetching token. Check network logs for more details.
+ ) : ( +
+ + + + {(creds.token_type || creds.scope) ?
+
+ {creds.token_type ?
+ Token Type: + {creds.token_type} +
: null} + {creds?.scope ?
+ Scope: + + {creds.scope} + +
: null} +
+
: null} +
+ ) ) : (
No token found
)} diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js index 68ae2cc50..47f6fc5b2 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js @@ -1,27 +1,20 @@ -import React, { useRef, forwardRef, useState, useMemo } from 'react'; +import React, { useRef, forwardRef } from 'react'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; -import { IconCaretDown, IconLoader2, IconSettings, IconKey, IconAdjustmentsHorizontal, IconHelp } from '@tabler/icons'; +import { IconCaretDown, IconSettings, IconKey, IconAdjustmentsHorizontal, IconHelp } from '@tabler/icons'; import SingleLineEditor from 'components/SingleLineEditor'; -import { fetchOauth2Credentials, clearOauth2Cache, refreshOauth2Credentials } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; import Dropdown from 'components/Dropdown'; import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; -import toast from 'react-hot-toast'; -import { cloneDeep } from 'lodash'; -import { getAllVariables } from 'utils/collections/index'; -import brunoCommon from '@usebruno/common'; -const { interpolate } = brunoCommon; +import Oauth2ActionButtons from '../Oauth2ActionButtons/index'; const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, updateAuth, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); const dropdownTippyRef = useRef(); const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - const [fetchingToken, toggleFetchingToken] = useState(false); - const [refreshingToken, toggleRefreshingToken] = useState(false); const oAuth = get(request, 'auth.oauth2', {}); @@ -45,45 +38,6 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update const refreshTokenUrlAvailable = refreshTokenUrl?.trim() !== ''; const isAutoRefreshDisabled = !refreshTokenUrlAvailable; - const interpolatedAccessTokenUrl = useMemo(() => { - const variables = getAllVariables(collection, item); - return interpolate(accessTokenUrl, variables); - }, [collection, item, accessTokenUrl]); - - const handleFetchOauth2Credentials = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleFetchingToken(true); - try { - await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); - toggleFetchingToken(false); - toast.success('Token fetched successfully!'); - } - catch (error) { - console.error(error); - toggleFetchingToken(false); - toast.error('An error occured while fetching token!'); - } - } - - const handleRefreshAccessToken = async () => { - let requestCopy = cloneDeep(request); - requestCopy.oauth2 = requestCopy?.auth.oauth2; - requestCopy.headers = {}; - toggleRefreshingToken(true); - try { - await dispatch(refreshOauth2Credentials({ request: requestCopy, collection })); - toggleRefreshingToken(false); - toast.success('token refreshed successfully!'); - } - catch(error) { - console.error(error); - toggleRefreshingToken(false); - toast.error('An error occured while refreshing token!'); - } - }; - const handleSave = () => { save(); } const TokenPlacementIcon = forwardRef((props, ref) => { @@ -132,16 +86,6 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update ); }; - const handleClearCache = (e) => { - dispatch(clearOauth2Cache({ collectionUid: collection?.uid, url: interpolatedAccessTokenUrl, credentialsId })) - .then(() => { - toast.success('cleared cache successfully'); - }) - .catch((err) => { - toast.error(err.message); - }); - }; - return ( @@ -354,18 +298,7 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update - -
- - - -
+
); }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index ace2beefd..fdf6b42c1 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -1293,7 +1293,7 @@ export const fetchOauth2Credentials = (payload) => async (dispatch, getState) => }; export const refreshOauth2Credentials = (payload) => async (dispatch, getState) => { - const { request, collection, folderUid, itemId } = payload; + const { request, collection, folderUid, itemUid } = payload; return new Promise((resolve, reject) => { window.ipcRenderer .invoke('renderer:refresh-oauth2-credentials', { request, collection }) @@ -1306,7 +1306,7 @@ export const refreshOauth2Credentials = (payload) => async (dispatch, getState) credentialsId, debugInfo, folderUid: folderUid || null, - itemId: !folderUid ? itemId : null + itemUid: !folderUid ? itemUid : null }) ); resolve(credentials); diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index d583fe261..5e8275ba1 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -1581,12 +1581,9 @@ export const collectionsSlice = createSlice({ }, updateFolderAuth: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); - - console.log('action.payload.content inside bro', action.payload); if (!collection) return; const folder = collection ? findItemInCollection(collection, action.payload.itemUid) : null; - console.log('folder inside bro', folder); if (!folder) return; if (folder) { diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 5b8318ed6..c1516af17 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -1026,8 +1026,8 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection collectionPath }); requestCopy = newRequest - let { credentials, url, credentialsId } = await refreshOauth2Token(requestCopy, collectionUid); - return { credentials, url, collectionUid, credentialsId }; + let { credentials, url, credentialsId, debugInfo } = await refreshOauth2Token(requestCopy, collectionUid); + return { credentials, url, collectionUid, credentialsId, debugInfo }; } } catch (error) { return Promise.reject(error); diff --git a/packages/bruno-electron/src/utils/oauth2.js b/packages/bruno-electron/src/utils/oauth2.js index ed9a46856..06b6dd779 100644 --- a/packages/bruno-electron/src/utils/oauth2.js +++ b/packages/bruno-electron/src/utils/oauth2.js @@ -8,6 +8,7 @@ const { safeParseJSON, safeStringifyJSON } = require('./common'); const oauth2Store = new Oauth2Store(); const persistOauth2Credentials = ({ collectionUid, url, credentials, credentialsId }) => { + if (credentials?.error || !credentials?.access_token) return; const enhancedCredentials = { ...credentials, created_at: Date.now(), @@ -20,8 +21,13 @@ const clearOauth2Credentials = ({ collectionUid, url, credentialsId }) => { }; const getStoredOauth2Credentials = ({ collectionUid, url, credentialsId }) => { - const credentials = oauth2Store.getCredentialsForCollection({ collectionUid, url, credentialsId }); - return credentials; + try { + const credentials = oauth2Store.getCredentialsForCollection({ collectionUid, url, credentialsId }); + return credentials; + } + catch(error) { + return null; + } }; const isTokenExpired = (credentials) => { @@ -675,18 +681,109 @@ const refreshOauth2Token = async (requestCopy, collectionUid) => { requestCopy.headers['Accept'] = 'application/json'; requestCopy.data = data; requestCopy.url = url; + requestCopy.responseType = 'arraybuffer'; + + // Initialize variables to hold request and response data for debugging + let axiosRequestInfo = null; + let axiosResponseInfo = null; + let debugInfo = { data: [] }; const axiosInstance = makeAxiosInstance(); + axiosInstance.interceptors.request.use((config) => { + const requestData = typeof config?.data === 'string' ? config?.data : safeStringifyJSON(config?.data); + axiosRequestInfo = { + method: config.method.toUpperCase(), + url: config.url, + headers: config.headers, + data: requestData, + dataBuffer: Buffer.from(requestData), + timestamp: Date.now(), + }; + return config; + }); + + // Interceptor to capture response data + axiosInstance.interceptors.response.use((response) => { + axiosResponseInfo = { + url: response?.url, + status: response.status, + statusText: response.statusText, + headers: response.headers, + data: response.data, + timestamp: Date.now(), + timeline: response?.timeline + }; + return response; + }, (error) => { + if (error.response) { + axiosResponseInfo = { + url: error?.response?.url, + status: error.response.status, + statusText: error.response.statusText, + headers: error.response.headers, + data: error.response.data, + timestamp: Date.now(), + timeline: error?.response?.timeline, + error: 'fetching access token failed! check timeline network logs' + }; + } + else if(error?.code) { + axiosResponseInfo = { + status: '-', + statusText: error.code, + headers: error?.config?.headers, + data: safeStringifyJSON(error?.errors), + timeline: error?.response?.timeline + }; + } + return axiosResponseInfo; + }); + + try { const response = await axiosInstance(requestCopy); - const responseData = Buffer.isBuffer(response.data) ? response.data.toString() : response.data; - const parsedResponseData = safeParseJSON(responseData); + const parsedResponseData = safeParseJSON( + Buffer.isBuffer(response.data) ? response.data.toString() : response.data + ); + + // Add the axios request and response info as a main request in debugInfo + const axiosMainRequest = { + requestId: Date.now().toString(), + request: { + url: axiosRequestInfo?.url, + method: axiosRequestInfo?.method, + headers: axiosRequestInfo?.headers || {}, + data: axiosRequestInfo?.data, + dataBuffer: axiosRequestInfo?.dataBuffer, + error: null + }, + response: { + url: axiosResponseInfo?.url, + headers: axiosResponseInfo?.headers, + data: parsedResponseData, + dataBuffer: axiosResponseInfo?.data, + status: axiosResponseInfo?.status, + statusText: axiosResponseInfo?.statusText, + timeline: axiosResponseInfo?.timeline, + error: null + }, + fromCache: false, + completed: true, + requests: [], // No sub-requests in this context + }; + + debugInfo.data.push(axiosMainRequest); + + if (parsedResponseData?.error) { + clearOauth2Credentials({ collectionUid, url, credentialsId }); + return { collectionUid, url, credentials: null, credentialsId, debugInfo }; + } persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId }); - return { collectionUid, url, credentials: parsedResponseData, credentialsId }; + return { collectionUid, url, credentials: parsedResponseData, credentialsId, debugInfo }; } catch (error) { clearOauth2Credentials({ collectionUid, url, credentialsId }); // Proceed without token - return { collectionUid, url, credentials: null, credentialsId }; + return { collectionUid, url, credentials: null, credentialsId, debugInfo }; } } };