mirror of
https://github.com/usebruno/bruno.git
synced 2025-05-05 15:32:58 +00:00
improve network error handling, oauth2 logic cleanup, tls settings, and ui/test updates (#4444)
~ axios error interceptor fixes and timeline network logs ui updates ~ axios instance error interceptor now returns promise rejects instead of plain objects ~ fixed digest_auth regression ~ removed the interceptor logic for the oauth2 token url calls ~ timeline network logs ui updates ~ updated oauth2 test collections * ssl/tls fixes and error handling ~ set the min allowed tls version to 1.0 (TLSv1) ~ proxy/certs/tls setup error handling * enhance JSON stringification with circular reference handling - Add getCircularReplacer to safely handle circular references in objects - Update safeStringifyJSON to support indentation and handle undefined values ~ we currently support digest auth for bruno-cli --------- Co-authored-by: lohit <lohit@usebruno.com> Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
This commit is contained in:
parent
9845363349
commit
2e5c63cfb9
@ -2,9 +2,17 @@ const Network = ({ logs }) => {
|
||||
return (
|
||||
<div className="bg-black/5 text-white network-logs rounded overflow-auto h-96">
|
||||
<pre className="whitespace-pre-wrap">
|
||||
{logs.map((entry, index) => (
|
||||
<NetworkLogsEntry key={index} entry={entry} />
|
||||
))}
|
||||
{logs.map((currentLog, index) => {
|
||||
if (index > 0 && currentLog?.type === 'separator') {
|
||||
return <div className="border-t-2 border-gray-500 w-full my-2" key={index} />;
|
||||
}
|
||||
const nextLog = logs[index + 1];
|
||||
const isSameLogType = nextLog?.type === currentLog?.type;
|
||||
return <>
|
||||
<NetworkLogsEntry key={index} entry={currentLog} />
|
||||
{!isSameLogType && <div className="mt-4"/>}
|
||||
</>;
|
||||
})}
|
||||
</pre>
|
||||
</div>
|
||||
)
|
||||
|
@ -141,7 +141,7 @@ const ResponsePane = ({ rightPaneWidth, item, collection }) => {
|
||||
)}
|
||||
{focusedTab?.responsePaneTab === "timeline" ? (
|
||||
<ClearTimeline item={item} collection={collection} />
|
||||
) : item?.response ? (
|
||||
) : (item?.response && !item?.response?.error) ? (
|
||||
<>
|
||||
<ResponseClear item={item} collection={collection} />
|
||||
<ResponseSave item={item} />
|
||||
|
@ -5,6 +5,10 @@ export const sendNetworkRequest = async (item, collection, environment, runtimeV
|
||||
if (['http-request', 'graphql-request'].includes(item.type)) {
|
||||
sendHttpRequest(item, collection, environment, runtimeVariables)
|
||||
.then((response) => {
|
||||
// if there is an error, we return the response object as is
|
||||
if (response?.error) {
|
||||
resolve(response)
|
||||
}
|
||||
resolve({
|
||||
state: 'success',
|
||||
data: response.data,
|
||||
|
@ -102,9 +102,12 @@ function makeAxiosInstance({
|
||||
const url = URL.parse(config.url);
|
||||
config.metadata = config.metadata || {};
|
||||
config.metadata.startTime = new Date().getTime();
|
||||
const timeline = config.metadata.timeline || []
|
||||
|
||||
const timeline = config.metadata.timeline || [];
|
||||
// Add initial request details to the timeline
|
||||
timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'separator'
|
||||
});
|
||||
timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
@ -173,10 +176,13 @@ function makeAxiosInstance({
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
if (err.timeline) {
|
||||
timeline = err.timeline;
|
||||
}
|
||||
timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: err?.message,
|
||||
message: `Error setting up proxy agents: ${err?.message}`,
|
||||
});
|
||||
}
|
||||
config.metadata.timeline = timeline;
|
||||
@ -264,21 +270,12 @@ function makeAxiosInstance({
|
||||
|
||||
if (redirectCount >= requestMaxRedirects) {
|
||||
const errorResponseData = error.response.data;
|
||||
const dataBuffer = Buffer.isBuffer(errorResponseData) ? errorResponseData : Buffer.from(errorResponseData);
|
||||
timeline?.push({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: safeStringifyJSON(errorResponseData?.toString?.())
|
||||
});
|
||||
return {
|
||||
status: error.response.status,
|
||||
statusText: error.response.statusText,
|
||||
headers: error.response.headers,
|
||||
data: errorResponseData?.toString?.(),
|
||||
size: Buffer.byteLength(dataBuffer),
|
||||
duration: error.response.headers.get('request-duration') ?? 0,
|
||||
timeline: error.response.timeline
|
||||
};
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
// Increase redirect count
|
||||
@ -319,14 +316,26 @@ function makeAxiosInstance({
|
||||
}
|
||||
}
|
||||
|
||||
setupProxyAgents({
|
||||
requestConfig,
|
||||
proxyMode,
|
||||
proxyConfig,
|
||||
httpsAgentRequestFields,
|
||||
interpolationOptions,
|
||||
timeline
|
||||
});
|
||||
try {
|
||||
setupProxyAgents({
|
||||
requestConfig,
|
||||
proxyMode,
|
||||
proxyConfig,
|
||||
httpsAgentRequestFields,
|
||||
interpolationOptions,
|
||||
timeline
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
if (err.timeline) {
|
||||
timeline = err.timeline;
|
||||
}
|
||||
timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `Error setting up proxy agents: ${err?.message}`,
|
||||
});
|
||||
}
|
||||
|
||||
requestConfig.metadata.timeline = timeline;
|
||||
// Make the redirected request
|
||||
@ -334,7 +343,11 @@ function makeAxiosInstance({
|
||||
}
|
||||
else {
|
||||
const errorResponseData = error.response.data;
|
||||
const dataBuffer = Buffer.isBuffer(errorResponseData) ? errorResponseData : Buffer.from(errorResponseData);
|
||||
timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'response',
|
||||
message: `HTTP/${error.response.httpVersion || '1.1'} ${error.response.status} ${error.response.statusText}`,
|
||||
});
|
||||
Object.entries(error?.response?.headers || {}).forEach(([key, value]) => {
|
||||
timeline.push({
|
||||
timestamp: new Date(),
|
||||
@ -357,15 +370,8 @@ function makeAxiosInstance({
|
||||
type: 'error',
|
||||
message: safeStringifyJSON(error?.errors)
|
||||
});
|
||||
return {
|
||||
status: error.response.status,
|
||||
statusText: error.response.statusText,
|
||||
headers: error.response.headers,
|
||||
data: errorResponseData?.toString?.(),
|
||||
size: Buffer.byteLength(dataBuffer),
|
||||
duration: error.response.headers.get('request-duration') ?? 0,
|
||||
timeline
|
||||
};
|
||||
error.response.timeline = timeline;
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
else if (error?.code) {
|
||||
@ -386,13 +392,9 @@ function makeAxiosInstance({
|
||||
type: 'error',
|
||||
message: safeStringifyJSON(error?.errors)
|
||||
});
|
||||
return {
|
||||
status: '-',
|
||||
statusText: error.code,
|
||||
headers: error?.config?.headers,
|
||||
data: 'request failed, check timeline network logs',
|
||||
timeline
|
||||
};
|
||||
error.timeline = timeline;
|
||||
error.statusText = error.code;
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ const { prepareRequest } = require('./prepare-request');
|
||||
const interpolateVars = require('./interpolate-vars');
|
||||
const { makeAxiosInstance } = require('./axios-instance');
|
||||
const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token');
|
||||
const { uuid, safeStringifyJSON, safeParseJSON, parseDataFromResponse } = require('../../utils/common');
|
||||
const { uuid, safeStringifyJSON, safeParseJSON, parseDataFromResponse, parseDataFromRequest } = require('../../utils/common');
|
||||
const { chooseFileToSave, writeBinaryFile, writeFile } = require('../../utils/filesystem');
|
||||
const { addCookieToJar, getDomainsWithCookies, getCookieStringForUrl } = require('../../utils/cookies');
|
||||
const { createFormData } = require('../../utils/form-data');
|
||||
@ -557,16 +557,14 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
processEnvVars,
|
||||
collectionPath
|
||||
);
|
||||
const requestData = request.mode == 'file'? "<request body redacted>": (typeof request?.data === 'string' ? request?.data : safeStringifyJSON(request?.data));
|
||||
|
||||
const { data: requestData, dataBuffer: requestDataBuffer } = parseDataFromRequest(request);
|
||||
let requestSent = {
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers: request.headers,
|
||||
data: requestData,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
if (requestData) {
|
||||
requestSent.dataBuffer = Buffer.from(requestData);
|
||||
dataBuffer: requestDataBuffer
|
||||
}
|
||||
|
||||
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||
@ -602,9 +600,14 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
|
||||
// if it's a cancel request, don't continue
|
||||
if (axios.isCancel(error)) {
|
||||
let error = new Error('Request cancelled');
|
||||
error.isCancel = true;
|
||||
return Promise.reject(error);
|
||||
// we are not rejecting the promise here and instead returning a response object with `error` which is handled in the `send-http-request` invocation
|
||||
// timeline prop won't be accessible in the usual way in the renderer process if we reject the promise
|
||||
return {
|
||||
statusText: 'REQUEST_CANCELLED',
|
||||
isCancel: true,
|
||||
error: 'REQUEST_CANCELLED',
|
||||
timeline: error.timeline
|
||||
};
|
||||
}
|
||||
|
||||
if (error?.response) {
|
||||
@ -615,7 +618,13 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
response.headers.delete('request-duration');
|
||||
} else {
|
||||
// if it's not a network error, don't continue
|
||||
return Promise.reject(error);
|
||||
// we are not rejecting the promise here and instead returning a response object with `error` which is handled in the `send-http-request` invocation
|
||||
// timeline prop won't be accessible in the usual way in the renderer process if we reject the promise
|
||||
return {
|
||||
statusText: error.statusText,
|
||||
error: error.message,
|
||||
timeline: error.timeline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -743,7 +752,13 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
} catch (error) {
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
|
||||
return Promise.reject(error);
|
||||
// we are not rejecting the promise here and instead returning a response object with `error` which is handled in the `send-http-request` invocation
|
||||
// timeline prop won't be accessible in the usual way in the renderer process if we reject the promise
|
||||
return {
|
||||
status: error?.status,
|
||||
error: error?.message || 'an error ocurred: debug',
|
||||
timeline: error?.timeline
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -992,15 +1007,13 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
continue;
|
||||
}
|
||||
|
||||
const requestData = request.mode == 'file'? "<request body redacted>": (typeof request?.data === 'string' ? request?.data : safeStringifyJSON(request?.data));
|
||||
const { data: requestData, dataBuffer: requestDataBuffer } = parseDataFromRequest(request);
|
||||
let requestSent = {
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers: request.headers,
|
||||
data: requestData
|
||||
}
|
||||
if (requestData) {
|
||||
requestSent.dataBuffer = Buffer.from(requestData);
|
||||
data: requestData,
|
||||
dataBuffer: requestDataBuffer
|
||||
}
|
||||
|
||||
// todo:
|
||||
|
@ -1,5 +1,6 @@
|
||||
const { customAlphabet } = require('nanoid');
|
||||
const iconv = require('iconv-lite');
|
||||
const { cloneDeep } = require('lodash');
|
||||
|
||||
// a customized version of nanoid without using _ and -
|
||||
const uuid = () => {
|
||||
@ -26,10 +27,24 @@ const parseJson = async (obj) => {
|
||||
}
|
||||
};
|
||||
|
||||
const safeStringifyJSON = (data) => {
|
||||
const getCircularReplacer = () => {
|
||||
const seen = new WeakSet();
|
||||
return (key, value) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (seen.has(value)) return "[Circular]";
|
||||
seen.add(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
const safeStringifyJSON = (data, indent = null) => {
|
||||
if (data === undefined) return undefined;
|
||||
try {
|
||||
return JSON.stringify(data);
|
||||
// getCircularReplacer - removes circular references that cause an error when stringifying
|
||||
return JSON.stringify(data, getCircularReplacer(), indent);
|
||||
} catch (e) {
|
||||
console.warn('Failed to stringify data:', e.message);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
@ -112,6 +127,16 @@ const parseDataFromResponse = (response, disableParsingResponseJson = false) =>
|
||||
return { data, dataBuffer };
|
||||
};
|
||||
|
||||
const parseDataFromRequest = (request) => {
|
||||
const requestDataString = request.mode == 'file'? "<request body redacted>": (typeof request?.data === 'string' ? request?.data : safeStringifyJSON(request?.data));
|
||||
const requestCopy = cloneDeep(request);
|
||||
if (!requestCopy.data) {
|
||||
return { data: null, dataBuffer: null };
|
||||
}
|
||||
requestCopy.data = requestDataString;
|
||||
return parseDataFromResponse(requestCopy);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
uuid,
|
||||
stringifyJson,
|
||||
@ -121,5 +146,6 @@ module.exports = {
|
||||
simpleHash,
|
||||
generateUidBasedOnHash,
|
||||
flattenDataForDotNotation,
|
||||
parseDataFromResponse
|
||||
parseDataFromResponse,
|
||||
parseDataFromRequest
|
||||
};
|
||||
|
@ -42,6 +42,10 @@ const isTokenExpired = (credentials) => {
|
||||
return Date.now() > expiryTime;
|
||||
};
|
||||
|
||||
const safeParseJSONBuffer = (data) => {
|
||||
return safeParseJSON(Buffer.isBuffer(data) ? data.toString() : data);
|
||||
}
|
||||
|
||||
// AUTHORIZATION CODE
|
||||
|
||||
const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, forceFetch = false, certsAndProxyConfig }) => {
|
||||
@ -143,68 +147,46 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo
|
||||
requestCopy.data = qs.stringify(data);
|
||||
requestCopy.url = url;
|
||||
requestCopy.responseType = 'arraybuffer';
|
||||
|
||||
// Initialize variables to hold request and response data for debugging
|
||||
let axiosRequestInfo = null;
|
||||
let axiosResponseInfo = null;
|
||||
|
||||
try {
|
||||
const { proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions } = certsAndProxyConfig;
|
||||
const axiosInstance = makeAxiosInstance({ proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions });
|
||||
// Interceptor to capture request data
|
||||
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,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
return config;
|
||||
});
|
||||
|
||||
// Interceptor to capture response data
|
||||
axiosInstance.interceptors.response.use((response) => {
|
||||
axiosResponseInfo = {
|
||||
let responseInfo, parsedResponseData;
|
||||
try {
|
||||
const response = await axiosInstance(requestCopy);
|
||||
parsedResponseData = safeParseJSONBuffer(response.data);
|
||||
responseInfo = {
|
||||
url: response?.url,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: response.headers,
|
||||
data: response.data,
|
||||
status: response?.status,
|
||||
statusText: response?.statusText,
|
||||
headers: response?.headers,
|
||||
data: parsedResponseData,
|
||||
timestamp: Date.now(),
|
||||
timeline: response?.timeline
|
||||
};
|
||||
return response;
|
||||
}, (error) => {
|
||||
}
|
||||
catch(error) {
|
||||
if (error.response) {
|
||||
axiosResponseInfo = {
|
||||
responseInfo = {
|
||||
url: error?.response?.url,
|
||||
status: error.response.status,
|
||||
statusText: error.response.statusText,
|
||||
headers: error.response.headers,
|
||||
data: error.response.data,
|
||||
status: error?.response?.status,
|
||||
statusText: error?.response?.statusText,
|
||||
headers: error?.response?.headers,
|
||||
data: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
timestamp: Date.now(),
|
||||
timeline: error?.response?.timeline,
|
||||
error: 'fetching access token failed! check timeline network logs'
|
||||
error: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
};
|
||||
}
|
||||
else if(error?.code) {
|
||||
axiosResponseInfo = {
|
||||
responseInfo = {
|
||||
status: '-',
|
||||
statusText: error.code,
|
||||
statusText: error?.code,
|
||||
headers: error?.config?.headers,
|
||||
data: safeStringifyJSON(error?.errors),
|
||||
timeline: error?.response?.timeline
|
||||
};
|
||||
}
|
||||
return axiosResponseInfo;
|
||||
});
|
||||
|
||||
const response = await axiosInstance(requestCopy);
|
||||
const parsedResponseData = safeParseJSON(
|
||||
Buffer.isBuffer(response.data) ? response.data?.toString() : response.data
|
||||
);
|
||||
}
|
||||
// Ensure debugInfo.data is initialized
|
||||
if (!debugInfo) {
|
||||
debugInfo = { data: [] };
|
||||
@ -216,33 +198,32 @@ const getOAuth2TokenUsingAuthorizationCode = async ({ request, collectionUid, fo
|
||||
const axiosMainRequest = {
|
||||
requestId: Date.now().toString(),
|
||||
request: {
|
||||
url: axiosRequestInfo?.url,
|
||||
method: axiosRequestInfo?.method,
|
||||
headers: axiosRequestInfo?.headers || {},
|
||||
data: axiosRequestInfo?.data,
|
||||
url: url,
|
||||
method: 'POST',
|
||||
headers: requestCopy?.headers,
|
||||
data: requestCopy?.data,
|
||||
error: null
|
||||
},
|
||||
response: {
|
||||
url: axiosResponseInfo?.url,
|
||||
headers: axiosResponseInfo?.headers,
|
||||
data: parsedResponseData,
|
||||
status: axiosResponseInfo?.status,
|
||||
statusText: axiosResponseInfo?.statusText,
|
||||
error: axiosResponseInfo?.error,
|
||||
timeline: axiosResponseInfo?.timeline
|
||||
url: responseInfo?.url,
|
||||
headers: responseInfo?.headers,
|
||||
data: responseInfo?.data,
|
||||
status: responseInfo?.status,
|
||||
statusText: responseInfo?.statusText,
|
||||
error: responseInfo?.error,
|
||||
timeline: responseInfo?.timeline
|
||||
},
|
||||
fromCache: false,
|
||||
completed: true,
|
||||
requests: [], // No sub-requests in this context
|
||||
};
|
||||
|
||||
debugInfo.data.push(axiosMainRequest);
|
||||
|
||||
persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
parsedResponseData && persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
|
||||
return { collectionUid, url, credentials: parsedResponseData, credentialsId, debugInfo };
|
||||
} catch (error) {
|
||||
return Promise.reject(safeStringifyJSON(error?.response?.data));
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -369,96 +350,79 @@ const getOAuth2TokenUsingClientCredentials = async ({ request, collectionUid, fo
|
||||
requestCopy.data = qs.stringify(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: [] };
|
||||
|
||||
try {
|
||||
const { proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions } = certsAndProxyConfig;
|
||||
const axiosInstance = makeAxiosInstance({ proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions });
|
||||
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,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
return config;
|
||||
});
|
||||
|
||||
// Interceptor to capture response data
|
||||
axiosInstance.interceptors.response.use((response) => {
|
||||
axiosResponseInfo = {
|
||||
let responseInfo, parsedResponseData;
|
||||
try {
|
||||
const response = await axiosInstance(requestCopy);
|
||||
parsedResponseData = safeParseJSONBuffer(response.data);
|
||||
responseInfo = {
|
||||
url: response?.url,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: response.headers,
|
||||
data: response.data,
|
||||
status: response?.status,
|
||||
statusText: response?.statusText,
|
||||
headers: response?.headers,
|
||||
data: parsedResponseData,
|
||||
timestamp: Date.now(),
|
||||
timeline: response?.timeline
|
||||
};
|
||||
return response;
|
||||
}, (error) => {
|
||||
}
|
||||
catch(error) {
|
||||
if (error.response) {
|
||||
axiosResponseInfo = {
|
||||
responseInfo = {
|
||||
url: error?.response?.url,
|
||||
status: error.response.status,
|
||||
statusText: error.response.statusText,
|
||||
headers: error.response.headers,
|
||||
data: error.response.data,
|
||||
status: error?.response?.status,
|
||||
statusText: error?.response?.statusText,
|
||||
headers: error?.response?.headers,
|
||||
data: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
timestamp: Date.now(),
|
||||
timeline: error?.response?.timeline,
|
||||
error: 'fetching access token failed! check timeline network logs'
|
||||
error: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
};
|
||||
}
|
||||
else if(error?.code) {
|
||||
axiosResponseInfo = {
|
||||
responseInfo = {
|
||||
status: '-',
|
||||
statusText: error.code,
|
||||
statusText: error?.code,
|
||||
headers: error?.config?.headers,
|
||||
data: safeStringifyJSON(error?.errors),
|
||||
timeline: error?.response?.timeline
|
||||
};
|
||||
}
|
||||
return axiosResponseInfo;
|
||||
});
|
||||
|
||||
const response = await axiosInstance(requestCopy);
|
||||
const parsedResponseData = safeParseJSON(
|
||||
Buffer.isBuffer(response.data) ? response.data.toString() : response.data
|
||||
);
|
||||
}
|
||||
if (!debugInfo) {
|
||||
debugInfo = { data: [] };
|
||||
} else if (!debugInfo.data) {
|
||||
debugInfo.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,
|
||||
url: url,
|
||||
method: 'POST',
|
||||
headers: requestCopy?.headers,
|
||||
data: requestCopy?.data,
|
||||
error: null
|
||||
},
|
||||
response: {
|
||||
url: axiosResponseInfo.url,
|
||||
headers: axiosResponseInfo?.headers,
|
||||
data: parsedResponseData,
|
||||
status: axiosResponseInfo?.status,
|
||||
statusText: axiosResponseInfo?.statusText,
|
||||
timeline: axiosResponseInfo?.timeline,
|
||||
error: null
|
||||
url: responseInfo?.url,
|
||||
headers: responseInfo?.headers,
|
||||
data: responseInfo?.data,
|
||||
status: responseInfo?.status,
|
||||
statusText: responseInfo?.statusText,
|
||||
error: responseInfo?.error,
|
||||
timeline: responseInfo?.timeline
|
||||
},
|
||||
fromCache: false,
|
||||
completed: true,
|
||||
requests: [], // No sub-requests in this context
|
||||
};
|
||||
|
||||
debugInfo.data.push(axiosMainRequest);
|
||||
|
||||
persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
parsedResponseData && persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
return { collectionUid, url, credentials: parsedResponseData, credentialsId, debugInfo };
|
||||
} catch (error) {
|
||||
return Promise.reject(safeStringifyJSON(error?.response?.data));
|
||||
@ -557,95 +521,79 @@ const getOAuth2TokenUsingPasswordCredentials = async ({ request, collectionUid,
|
||||
requestCopy.data = qs.stringify(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: [] };
|
||||
|
||||
try {
|
||||
const { proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions } = certsAndProxyConfig;
|
||||
const axiosInstance = makeAxiosInstance({ proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions });
|
||||
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,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
return config;
|
||||
});
|
||||
|
||||
// Interceptor to capture response data
|
||||
axiosInstance.interceptors.response.use((response) => {
|
||||
axiosResponseInfo = {
|
||||
let responseInfo, parsedResponseData;
|
||||
try {
|
||||
const response = await axiosInstance(requestCopy);
|
||||
parsedResponseData = safeParseJSONBuffer(response.data);
|
||||
responseInfo = {
|
||||
url: response?.url,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: response.headers,
|
||||
data: response.data,
|
||||
status: response?.status,
|
||||
statusText: response?.statusText,
|
||||
headers: response?.headers,
|
||||
data: parsedResponseData,
|
||||
timestamp: Date.now(),
|
||||
timeline: response?.timeline
|
||||
};
|
||||
return response;
|
||||
}, (error) => {
|
||||
}
|
||||
catch(error) {
|
||||
if (error.response) {
|
||||
axiosResponseInfo = {
|
||||
responseInfo = {
|
||||
url: error?.response?.url,
|
||||
status: error.response.status,
|
||||
statusText: error.response.statusText,
|
||||
headers: error.response.headers,
|
||||
data: error.response.data,
|
||||
status: error?.response?.status,
|
||||
statusText: error?.response?.statusText,
|
||||
headers: error?.response?.headers,
|
||||
data: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
timestamp: Date.now(),
|
||||
timeline: error?.response?.timeline,
|
||||
error: 'fetching access token failed! check timeline network logs'
|
||||
error: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
};
|
||||
}
|
||||
else if(error?.code) {
|
||||
axiosResponseInfo = {
|
||||
responseInfo = {
|
||||
status: '-',
|
||||
statusText: error.code,
|
||||
statusText: error?.code,
|
||||
headers: error?.config?.headers,
|
||||
data: safeStringifyJSON(error?.errors),
|
||||
timeline: error?.response?.timeline
|
||||
};
|
||||
}
|
||||
return axiosResponseInfo;
|
||||
});
|
||||
const response = await axiosInstance(requestCopy);
|
||||
const parsedResponseData = safeParseJSON(
|
||||
Buffer.isBuffer(response.data) ? response.data.toString() : response.data
|
||||
);
|
||||
}
|
||||
if (!debugInfo) {
|
||||
debugInfo = { data: [] };
|
||||
} else if (!debugInfo.data) {
|
||||
debugInfo.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,
|
||||
url: url,
|
||||
method: 'POST',
|
||||
headers: requestCopy?.headers,
|
||||
data: requestCopy?.data,
|
||||
error: null
|
||||
},
|
||||
response: {
|
||||
url: axiosResponseInfo?.url,
|
||||
headers: axiosResponseInfo?.headers,
|
||||
data: parsedResponseData,
|
||||
status: axiosResponseInfo?.status,
|
||||
statusText: axiosResponseInfo?.statusText,
|
||||
timeline: axiosResponseInfo?.timeline,
|
||||
error: null
|
||||
url: responseInfo?.url,
|
||||
headers: responseInfo?.headers,
|
||||
data: responseInfo?.data,
|
||||
status: responseInfo?.status,
|
||||
statusText: responseInfo?.statusText,
|
||||
error: responseInfo?.error,
|
||||
timeline: responseInfo?.timeline
|
||||
},
|
||||
fromCache: false,
|
||||
completed: true,
|
||||
requests: [], // No sub-requests in this context
|
||||
};
|
||||
|
||||
debugInfo.data.push(axiosMainRequest);
|
||||
|
||||
persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
parsedResponseData && persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
return { collectionUid, url, credentials: parsedResponseData, credentialsId, debugInfo };
|
||||
} catch (error) {
|
||||
return Promise.reject(safeStringifyJSON(error?.response?.data));
|
||||
@ -677,101 +625,82 @@ const refreshOauth2Token = async ({ requestCopy, collectionUid, certsAndProxyCon
|
||||
requestCopy.data = qs.stringify(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 { proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions } = certsAndProxyConfig;
|
||||
const axiosInstance = makeAxiosInstance({ proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions });
|
||||
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,
|
||||
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 parsedResponseData = safeParseJSON(
|
||||
Buffer.isBuffer(response.data) ? response.data.toString() : response.data
|
||||
);
|
||||
const { proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions } = certsAndProxyConfig;
|
||||
const axiosInstance = makeAxiosInstance({ proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions });
|
||||
let responseInfo, parsedResponseData;
|
||||
try {
|
||||
const response = await axiosInstance(requestCopy);
|
||||
parsedResponseData = safeParseJSONBuffer(response.data);
|
||||
responseInfo = {
|
||||
url: response?.url,
|
||||
status: response?.status,
|
||||
statusText: response?.statusText,
|
||||
headers: response?.headers,
|
||||
data: parsedResponseData,
|
||||
timestamp: Date.now(),
|
||||
timeline: response?.timeline
|
||||
};
|
||||
}
|
||||
catch(error) {
|
||||
if (error.response) {
|
||||
responseInfo = {
|
||||
url: error?.response?.url,
|
||||
status: error?.response?.status,
|
||||
statusText: error?.response?.statusText,
|
||||
headers: error?.response?.headers,
|
||||
data: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
timestamp: Date.now(),
|
||||
timeline: error?.response?.timeline,
|
||||
error: safeStringifyJSON(safeParseJSONBuffer(error?.response?.data)),
|
||||
};
|
||||
}
|
||||
else if(error?.code) {
|
||||
responseInfo = {
|
||||
status: '-',
|
||||
statusText: error?.code,
|
||||
headers: error?.config?.headers,
|
||||
data: safeStringifyJSON(error?.errors),
|
||||
timeline: error?.response?.timeline
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!debugInfo) {
|
||||
debugInfo = { data: [] };
|
||||
} else if (!debugInfo.data) {
|
||||
debugInfo.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,
|
||||
url: url,
|
||||
method: 'POST',
|
||||
headers: requestCopy?.headers,
|
||||
data: requestCopy?.data,
|
||||
error: null
|
||||
},
|
||||
response: {
|
||||
url: axiosResponseInfo?.url,
|
||||
headers: axiosResponseInfo?.headers,
|
||||
data: parsedResponseData,
|
||||
status: axiosResponseInfo?.status,
|
||||
statusText: axiosResponseInfo?.statusText,
|
||||
timeline: axiosResponseInfo?.timeline,
|
||||
error: null
|
||||
url: responseInfo?.url,
|
||||
headers: responseInfo?.headers,
|
||||
data: responseInfo?.data,
|
||||
status: responseInfo?.status,
|
||||
statusText: responseInfo?.statusText,
|
||||
error: responseInfo?.error,
|
||||
timeline: responseInfo?.timeline
|
||||
},
|
||||
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 });
|
||||
parsedResponseData && persistOauth2Credentials({ collectionUid, url, credentials: parsedResponseData, credentialsId });
|
||||
return { collectionUid, url, credentials: parsedResponseData, credentialsId, debugInfo };
|
||||
} catch (error) {
|
||||
clearOauth2Credentials({ collectionUid, url, credentialsId });
|
||||
|
@ -168,10 +168,21 @@ function createTimelineAgentClass(BaseAgentClass) {
|
||||
message: `Trying ${host}:${port}...`,
|
||||
});
|
||||
|
||||
const socket = super.createConnection(options, callback);
|
||||
let socket;
|
||||
try {
|
||||
socket = super.createConnection(options, callback);
|
||||
} catch (error) {
|
||||
this.timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `Error creating connection: ${error.message}`,
|
||||
});
|
||||
error.timeline = this.timeline;
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Attach event listeners to the socket
|
||||
socket.on('lookup', (err, address, family, host) => {
|
||||
socket?.on('lookup', (err, address, family, host) => {
|
||||
if (err) {
|
||||
this.timeline.push({
|
||||
timestamp: new Date(),
|
||||
@ -187,7 +198,7 @@ function createTimelineAgentClass(BaseAgentClass) {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket?.on('connect', () => {
|
||||
const address = socket.remoteAddress || host;
|
||||
const remotePort = socket.remotePort || port;
|
||||
|
||||
@ -198,7 +209,7 @@ function createTimelineAgentClass(BaseAgentClass) {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('secureConnect', () => {
|
||||
socket?.on('secureConnect', () => {
|
||||
const protocol = socket.getProtocol() || 'SSL/TLS';
|
||||
const cipher = socket.getCipher();
|
||||
const cipherSuite = cipher ? `${cipher.name} (${cipher.version})` : 'Unknown cipher';
|
||||
@ -270,7 +281,7 @@ function createTimelineAgentClass(BaseAgentClass) {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('error', (err) => {
|
||||
socket?.on('error', (err) => {
|
||||
this.timeline.push({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
@ -294,6 +305,10 @@ function setupProxyAgents({
|
||||
// Ensure TLS options are properly set
|
||||
const tlsOptions = {
|
||||
...httpsAgentRequestFields,
|
||||
// Enable all secure protocols by default
|
||||
secureProtocol: undefined,
|
||||
// Allow Node.js to choose the protocol
|
||||
minVersion: 'TLSv1',
|
||||
rejectUnauthorized: httpsAgentRequestFields.rejectUnauthorized !== undefined ? httpsAgentRequestFields.rejectUnauthorized : true,
|
||||
};
|
||||
|
||||
|
@ -7,8 +7,9 @@ auth:oauth2 {
|
||||
callback_url: {{key-host}}/realms/bruno/account
|
||||
authorization_url: {{key-host}}/realms/bruno/protocol/openid-connect/auth
|
||||
access_token_url: {{key-host}}/realms/bruno/protocol/openid-connect/token
|
||||
refresh_token_url:
|
||||
client_id: account
|
||||
client_secret: Lh3NkRikMZpO12rwSBwVimde9v89B5Rw
|
||||
client_secret: {{client_secret}}
|
||||
scope: openid
|
||||
state:
|
||||
pkce: true
|
||||
@ -16,5 +17,6 @@ auth:oauth2 {
|
||||
credentials_id: credentials
|
||||
token_placement: header
|
||||
token_header_prefix: Bearer
|
||||
reuse_token:
|
||||
auto_fetch_token: true
|
||||
auto_refresh_token: false
|
||||
}
|
||||
|
@ -1,21 +1,6 @@
|
||||
vars {
|
||||
host: http://localhost:8081
|
||||
bearer_auth_token: your_secret_token
|
||||
basic_auth_password: della
|
||||
client_id: client_id_1
|
||||
client_secret: client_secret_1
|
||||
password_credentials_access_token_url: http://localhost:8081/api/auth/oauth2/password_credentials/token
|
||||
password_credentials_username: foo
|
||||
password_credentials_password: bar
|
||||
password_credentials_scope:
|
||||
authorization_code_authorize_url: http://localhost:8081/api/auth/oauth2/authorization_code/authorize
|
||||
authorization_code_callback_url: http://localhost:8081/api/auth/oauth2/authorization_code/callback
|
||||
authorization_code_access_token_url: http://localhost:8081/api/auth/oauth2/authorization_code/token
|
||||
authorization_code_access_token: null
|
||||
client_credentials_access_token_url: http://localhost:8081/api/auth/oauth2/client_credentials/token
|
||||
client_credentials_client_id: client_id_1
|
||||
client_credentials_client_secret: client_secret_1
|
||||
client_credentials_scope: admin
|
||||
client_credentials_access_token: 870132a2ed28a3c94d34f868e6514720
|
||||
key-host: http://localhost:8080
|
||||
}
|
||||
vars:secret [
|
||||
client_secret
|
||||
]
|
||||
|
@ -17,7 +17,7 @@ auth:oauth2 {
|
||||
access_token_url: {{key-host}}/realms/bruno/protocol/openid-connect/token
|
||||
refresh_token_url:
|
||||
client_id: account
|
||||
client_secret: Lh3NkRikMZpO12rwSBwVimde9v89B5Rw
|
||||
client_secret: {{client_secret}}
|
||||
scope: openid
|
||||
state:
|
||||
pkce: true
|
||||
|
@ -3,18 +3,16 @@ auth {
|
||||
}
|
||||
|
||||
auth:oauth2 {
|
||||
grant_type: authorization_code
|
||||
callback_url: {{key-host}}/realms/bruno/account
|
||||
authorization_url: {{key-host}}/realms/bruno/protocol/openid-connect/auth
|
||||
grant_type: client_credentials
|
||||
access_token_url: {{key-host}}/realms/bruno/protocol/openid-connect/token
|
||||
refresh_token_url:
|
||||
client_id: account
|
||||
client_secret: Lh3NkRikMZpO12rwSBwVimde9v89B5Rw
|
||||
client_secret: {{client_secret}}
|
||||
scope: openid
|
||||
state:
|
||||
pkce: true
|
||||
tokenId: keycloak
|
||||
tokenPlacement: header
|
||||
tokenHeaderPrefix: Bearer
|
||||
tokenQueryKey: access_token
|
||||
reuseToken:
|
||||
credentials_placement: body
|
||||
credentials_id: credentials
|
||||
token_placement: header
|
||||
token_header_prefix: Bearer
|
||||
auto_fetch_token: true
|
||||
auto_refresh_token: false
|
||||
}
|
||||
|
@ -1,22 +1,6 @@
|
||||
vars {
|
||||
host: http://localhost:8080
|
||||
bearer_auth_token: your_secret_token
|
||||
basic_auth_password: della
|
||||
client_id: client_id_1
|
||||
client_secret: client_secret_1
|
||||
password_credentials_access_token_url: http://localhost:8081/api/auth/oauth2/password_credentials/token
|
||||
password_credentials_username: foo
|
||||
password_credentials_password: bar
|
||||
password_credentials_scope:
|
||||
authorization_code_authorize_url: http://localhost:8081/api/auth/oauth2/authorization_code/authorize
|
||||
authorization_code_callback_url: http://localhost:8081/api/auth/oauth2/authorization_code/callback
|
||||
authorization_code_access_token_url: http://localhost:8081/api/auth/oauth2/authorization_code/token
|
||||
authorization_code_access_token: null
|
||||
client_credentials_access_token_url: http://localhost:8081/api/auth/oauth2/client_credentials/token
|
||||
client_credentials_client_id: client_id_1
|
||||
client_credentials_client_secret: client_secret_1
|
||||
client_credentials_scope: admin
|
||||
client_credentials_access_token: 870132a2ed28a3c94d34f868e6514720
|
||||
key-host: http://localhost:8080
|
||||
key-host-1: http://localhost:8082
|
||||
}
|
||||
vars:secret [
|
||||
client_secret
|
||||
]
|
||||
|
@ -11,5 +11,5 @@ get {
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{$oauth2.keycloak.access_token}}
|
||||
token: {{$oauth2.credentials.access_token}}
|
||||
}
|
||||
|
@ -13,12 +13,14 @@ get {
|
||||
auth:oauth2 {
|
||||
grant_type: client_credentials
|
||||
access_token_url: {{key-host}}/realms/bruno/protocol/openid-connect/token
|
||||
refresh_token_url:
|
||||
client_id: account
|
||||
client_secret: Lh3NkRikMZpO12rwSBwVimde9v89B5Rw
|
||||
client_secret: {{client_secret}}a
|
||||
scope: openid
|
||||
credentials_placement: body
|
||||
credentials_id: credentials
|
||||
token_placement: header
|
||||
token_header_prefix: Bearer
|
||||
reuse_token:
|
||||
auto_fetch_token: true
|
||||
auto_refresh_token: false
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "keycloak-password-credentials",
|
||||
"type": "collection",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
".git"
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
auth {
|
||||
mode: oauth2
|
||||
}
|
||||
|
||||
auth:oauth2 {
|
||||
grant_type: password
|
||||
access_token_url: {{key-host}}/realms/bruno/protocol/openid-connect/token
|
||||
refresh_token_url:
|
||||
username: bruno
|
||||
password: bruno
|
||||
client_id: account
|
||||
client_secret: {{client_secret}}
|
||||
scope: openid
|
||||
credentials_placement: body
|
||||
credentials_id: credentials
|
||||
token_placement: header
|
||||
token_header_prefix: Bearer
|
||||
auto_fetch_token: true
|
||||
auto_refresh_token: false
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
vars {
|
||||
key-host: http://localhost:8080
|
||||
}
|
||||
vars:secret [
|
||||
client_secret
|
||||
]
|
@ -0,0 +1,11 @@
|
||||
meta {
|
||||
name: user_info_coll-auth
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{key-host}}/realms/bruno/protocol/openid-connect/userinfo
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: user_info_custom
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{key-host}}/realms/bruno/protocol/openid-connect/userinfo
|
||||
body: none
|
||||
auth: bearer
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token: {{$oauth2.credentials.access_token}}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
meta {
|
||||
name: user_info_request-auth
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{key-host}}/realms/bruno/protocol/openid-connect/userinfo
|
||||
body: none
|
||||
auth: oauth2
|
||||
}
|
||||
|
||||
auth:oauth2 {
|
||||
grant_type: password
|
||||
access_token_url: {{key-host}}/realms/bruno/protocol/openid-connect/token
|
||||
refresh_token_url:
|
||||
username: admin
|
||||
password: admin
|
||||
client_id: account
|
||||
client_secret: {{client_secret}}
|
||||
scope: openid
|
||||
credentials_placement: body
|
||||
credentials_id: credentials
|
||||
token_placement: header
|
||||
token_header_prefix: Bearer
|
||||
auto_fetch_token: true
|
||||
auto_refresh_token: false
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user