diff --git a/package-lock.json b/package-lock.json index d60271467..ba28f874f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "@eslint/compat": "^1.3.2", "@faker-js/faker": "^7.6.0", "@jest/globals": "^29.2.0", - "@opencollection/types": "~0.7.0", + "@opencollection/types": "~0.8.0", "@playwright/test": "^1.51.1", "@rollup/plugin-json": "^6.1.0", "@storybook/addon-webpack5-compiler-babel": "^4.0.0", @@ -6136,9 +6136,9 @@ } }, "node_modules/@opencollection/types": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.7.0.tgz", - "integrity": "sha512-CSwdaHNPa2bNNBAOy++t6W9gBTExUJZW3aPkWyhAjasusThbvjymD/0uCLR50gCXSs0ezv61jsd19m9x+2DMtQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.8.0.tgz", + "integrity": "sha512-YnogiJdyN/BTf9lu+eTwmhAOiOwAT2cuPXv7ePvQsVT6r6gCALDR2IhD8ISergR/fQBgELWvlfj+lh/qTQ6sZw==", "dev": true, "license": "MIT" }, @@ -33376,7 +33376,7 @@ "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.4", - "@opencollection/types": "~0.5.0", + "@opencollection/types": "~0.8.0", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-commonjs": "^23.0.2", "@rollup/plugin-node-resolve": "^15.0.1", @@ -33392,13 +33392,6 @@ "typescript": "^4.8.4" } }, - "packages/bruno-converters/node_modules/@opencollection/types": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.5.0.tgz", - "integrity": "sha512-9rpu5agMrMLcMVU2UgyV+PYV3Zf/sHBJDHMQoq8XiMEUH8lt9f7yGtlerm/9dS3SHMpGX4A8ik0OFtc0dX4r1Q==", - "dev": true, - "license": "MIT" - }, "packages/bruno-converters/node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", diff --git a/package.json b/package.json index 2b92e7ed6..c2205e816 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@eslint/compat": "^1.3.2", "@faker-js/faker": "^7.6.0", "@jest/globals": "^29.2.0", - "@opencollection/types": "~0.7.0", + "@opencollection/types": "~0.8.0", "@playwright/test": "^1.51.1", "@rollup/plugin-json": "^6.1.0", "@storybook/addon-webpack5-compiler-babel": "^4.0.0", 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 57e9710bf..274b7479b 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,10 +1,10 @@ -import React, { useRef, forwardRef } from 'react'; +import React from 'react'; import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch, useSelector } from 'react-redux'; import { IconCaretDown, IconSettings, IconKey, IconHelp, IconAdjustmentsHorizontal } from '@tabler/icons'; -import Dropdown from 'components/Dropdown'; +import MenuDropdown from 'ui/MenuDropdown'; import SingleLineEditor from 'components/SingleLineEditor'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; @@ -20,8 +20,6 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu const preferences = useSelector((state) => state.app.preferences); const { storedTheme } = useTheme(); const useSystemBrowser = get(preferences, 'request.oauth2.useSystemBrowser', false); - const dropdownTippyRef = useRef(); - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); const { isSensitive } = useDetectSensitiveField(collection); const oAuth = get(request, 'auth.oauth2', {}); const { @@ -41,30 +39,13 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu refreshTokenUrl, autoRefreshToken, autoFetchToken, + tokenSource, additionalParameters } = oAuth; const refreshTokenUrlAvailable = refreshTokenUrl?.trim() !== ''; const isAutoRefreshDisabled = !refreshTokenUrlAvailable; - const TokenPlacementIcon = forwardRef((props, ref) => { - return ( -
- {tokenPlacement == 'url' ? 'URL' : 'Headers'} - -
- ); - }); - - const CredentialsPlacementIcon = forwardRef((props, ref) => { - return ( -
- {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} - -
- ); - }); - const handleSave = () => { save(); }; const handleChange = (key, value) => { @@ -91,6 +72,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu refreshTokenUrl, autoRefreshToken, autoFetchToken, + tokenSource, additionalParameters, [key]: value } @@ -119,6 +101,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu tokenHeaderPrefix, tokenQueryKey, autoFetchToken, + tokenSource, additionalParameters, pkce: !Boolean(oAuth?.['pkce']) } @@ -226,26 +209,19 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('credentialsPlacement', 'body'); - }} - > - Request Body + handleChange('credentialsPlacement', 'body') }, + { id: 'basic_auth_header', label: 'Basic Auth Header', onClick: () => handleChange('credentialsPlacement', 'basic_auth_header') } + ]} + selectedItemId={credentialsPlacement} + placement="bottom-end" + > +
+ {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('credentialsPlacement', 'basic_auth_header'); - }} - > - Basic Auth Header -
- +
@@ -265,6 +241,24 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu Token
+
+ +
+ handleChange('tokenSource', 'access_token') }, + { id: 'id_token', label: 'ID Token', onClick: () => handleChange('tokenSource', 'id_token') } + ]} + selectedItemId={tokenSource} + placement="bottom-end" + > +
+ {tokenSource === 'id_token' ? 'ID Token' : 'Access Token'} + +
+
+
+
@@ -283,26 +277,19 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'header'); - }} - > - Header + handleChange('tokenPlacement', 'header') }, + { id: 'url', label: 'URL', onClick: () => handleChange('tokenPlacement', 'url') } + ]} + selectedItemId={tokenPlacement} + placement="bottom-end" + > +
+ {tokenPlacement == 'url' ? 'URL' : 'Headers'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'url'); - }} - > - URL -
- +
{ 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 b1d96bab1..48e01ae07 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,4 +1,4 @@ -import React, { useRef, forwardRef } from 'react'; +import React from 'react'; import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; @@ -7,7 +7,7 @@ import { IconCaretDown, IconSettings, IconKey, IconAdjustmentsHorizontal, IconHe import SingleLineEditor from 'components/SingleLineEditor'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; -import Dropdown from 'components/Dropdown'; +import MenuDropdown from 'ui/MenuDropdown'; import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; import Oauth2ActionButtons from '../Oauth2ActionButtons/index'; import AdditionalParams from '../AdditionalParams/index'; @@ -16,8 +16,6 @@ import SensitiveFieldWarning from 'components/SensitiveFieldWarning'; const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAuth, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); - const dropdownTippyRef = useRef(); - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); const { isSensitive } = useDetectSensitiveField(collection); const oAuth = get(request, 'auth.oauth2', {}); @@ -34,6 +32,7 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu refreshTokenUrl, autoRefreshToken, autoFetchToken, + tokenSource, additionalParameters } = oAuth; @@ -42,24 +41,6 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu const handleSave = () => { save(); }; - const TokenPlacementIcon = forwardRef((props, ref) => { - return ( -
- {tokenPlacement == 'url' ? 'URL' : 'Headers'} - -
- ); - }); - - const CredentialsPlacementIcon = forwardRef((props, ref) => { - return ( -
- {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} - -
- ); - }); - const handleChange = (key, value) => { dispatch( updateAuth({ @@ -80,6 +61,7 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu refreshTokenUrl, autoRefreshToken, autoFetchToken, + tokenSource, additionalParameters, [key]: value } @@ -126,26 +108,19 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('credentialsPlacement', 'body'); - }} - > - Request Body + handleChange('credentialsPlacement', 'body') }, + { id: 'basic_auth_header', label: 'Basic Auth Header', onClick: () => handleChange('credentialsPlacement', 'basic_auth_header') } + ]} + selectedItemId={credentialsPlacement} + placement="bottom-end" + > +
+ {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('credentialsPlacement', 'basic_auth_header'); - }} - > - Basic Auth Header -
- +
@@ -156,6 +131,24 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu Token
+
+ +
+ handleChange('tokenSource', 'access_token') }, + { id: 'id_token', label: 'ID Token', onClick: () => handleChange('tokenSource', 'id_token') } + ]} + selectedItemId={tokenSource} + placement="bottom-end" + > +
+ {tokenSource === 'id_token' ? 'ID Token' : 'Access Token'} + +
+
+
+
@@ -174,26 +167,19 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'header'); - }} - > - Header + handleChange('tokenPlacement', 'header') }, + { id: 'url', label: 'URL', onClick: () => handleChange('tokenPlacement', 'url') } + ]} + selectedItemId={tokenPlacement} + placement="bottom-end" + > +
+ {tokenPlacement == 'url' ? 'URL' : 'Headers'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'url'); - }} - > - URL -
- +
{ diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/GrantTypeSelector/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/GrantTypeSelector/index.js index 3e005849e..d6417f747 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/GrantTypeSelector/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/GrantTypeSelector/index.js @@ -1,6 +1,6 @@ -import React, { useRef, forwardRef } from 'react'; +import React from 'react'; import get from 'lodash/get'; -import Dropdown from 'components/Dropdown'; +import MenuDropdown from 'ui/MenuDropdown'; import { useDispatch } from 'react-redux'; import StyledWrapper from './StyledWrapper'; import { IconCaretDown, IconKey } from '@tabler/icons'; @@ -10,20 +10,10 @@ import { useState } from 'react'; const GrantTypeSelector = ({ item = {}, request, updateAuth, collection }) => { const dispatch = useDispatch(); - const dropdownTippyRef = useRef(); const oAuth = get(request, 'auth.oauth2', {}); const [valuesCache, setValuesCache] = useState({ ...oAuth }); - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - - const Icon = forwardRef((props, ref) => { - return ( -
- {humanizeGrantType(oAuth?.grantType)} -
- ); - }); const onGrantTypeChange = (grantType) => { let updatedValues = { @@ -65,7 +55,8 @@ const GrantTypeSelector = ({ item = {}, request, updateAuth, collection }) => { credentialsId: 'credentials', tokenPlacement: 'header', tokenHeaderPrefix: 'Bearer', - tokenQueryKey: 'access_token' + tokenQueryKey: 'access_token', + tokenSource: 'access_token' } }) ); @@ -82,44 +73,20 @@ const GrantTypeSelector = ({ item = {}, request, updateAuth, collection }) => {
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('password'); - }} - > - Password Credentials + onGrantTypeChange('password') }, + { id: 'authorization_code', label: 'Authorization Code', onClick: () => onGrantTypeChange('authorization_code') }, + { id: 'implicit', label: 'Implicit', onClick: () => onGrantTypeChange('implicit') }, + { id: 'client_credentials', label: 'Client Credentials', onClick: () => onGrantTypeChange('client_credentials') } + ]} + selectedItemId={oAuth?.grantType} + placement="bottom-end" + > +
+ {humanizeGrantType(oAuth?.grantType)}
-
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('authorization_code'); - }} - > - Authorization Code -
-
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('implicit'); - }} - > - Implicit -
-
{ - dropdownTippyRef.current.hide(); - onGrantTypeChange('client_credentials'); - }} - > - Client Credentials -
- +
); diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Implicit/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Implicit/index.js index 13cd28f24..807a255f8 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Implicit/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/Implicit/index.js @@ -1,9 +1,9 @@ -import React, { useRef, forwardRef, useMemo } from 'react'; +import React, { useMemo } from 'react'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; import { useDispatch, useSelector } from 'react-redux'; import { IconCaretDown, IconSettings, IconKey, IconHelp, IconAdjustmentsHorizontal } from '@tabler/icons'; -import Dropdown from 'components/Dropdown'; +import MenuDropdown from 'ui/MenuDropdown'; import SingleLineEditor from 'components/SingleLineEditor'; import Wrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; @@ -20,9 +20,6 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle const preferences = useSelector((state) => state.app.preferences); const useSystemBrowser = get(preferences, 'request.oauth2.useSystemBrowser', false); const { storedTheme } = useTheme(); - const dropdownTippyRef = useRef(); - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - const oAuth = get(request, 'auth.oauth2', {}); const { callbackUrl, @@ -34,7 +31,8 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle tokenPlacement, tokenHeaderPrefix, tokenQueryKey, - autoFetchToken + autoFetchToken, + tokenSource } = oAuth; const interpolatedAuthUrl = useMemo(() => { @@ -42,15 +40,6 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle return interpolate(authorizationUrl, variables); }, [collection, item, authorizationUrl]); - const TokenPlacementIcon = forwardRef((props, ref) => { - return ( -
- {tokenPlacement == 'url' ? 'URL' : 'Headers'} - -
- ); - }); - const handleSave = () => { save(); }; const handleChange = (key, value) => { @@ -71,6 +60,7 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle tokenHeaderPrefix, tokenQueryKey, autoFetchToken, + tokenSource, [key]: value } }) @@ -184,6 +174,25 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle
+
+ +
+ handleChange('tokenSource', 'access_token') }, + { id: 'id_token', label: 'ID Token', onClick: () => handleChange('tokenSource', 'id_token') } + ]} + selectedItemId={tokenSource} + placement="bottom-end" + > +
+ {tokenSource === 'id_token' ? 'ID Token' : 'Access Token'} + +
+
+
+
+
@@ -203,26 +212,19 @@ const OAuth2Implicit = ({ save, item = {}, request, handleRun, updateAuth, colle
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'header'); - }} - > - Headers + handleChange('tokenPlacement', 'header') }, + { id: 'url', label: 'URL', onClick: () => handleChange('tokenPlacement', 'url') } + ]} + selectedItemId={tokenPlacement} + placement="bottom-end" + > +
+ {tokenPlacement == 'url' ? 'URL' : 'Headers'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'url'); - }} - > - URL -
- +
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 b3caf51b3..ab3adfd8e 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,4 +1,4 @@ -import React, { useRef, forwardRef } from 'react'; +import React from 'react'; import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField'; import get from 'lodash/get'; import { useTheme } from 'providers/Theme'; @@ -7,7 +7,7 @@ import { IconCaretDown, IconSettings, IconKey, IconAdjustmentsHorizontal, IconHe import SingleLineEditor from 'components/SingleLineEditor'; import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; -import Dropdown from 'components/Dropdown'; +import MenuDropdown from 'ui/MenuDropdown'; import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; import Oauth2ActionButtons from '../Oauth2ActionButtons/index'; import AdditionalParams from '../AdditionalParams/index'; @@ -16,8 +16,6 @@ import SensitiveFieldWarning from 'components/SensitiveFieldWarning/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 oAuth = get(request, 'auth.oauth2', {}); const { isSensitive } = useDetectSensitiveField(collection); @@ -36,6 +34,7 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update refreshTokenUrl, autoRefreshToken, autoFetchToken, + tokenSource, additionalParameters } = oAuth; @@ -44,24 +43,6 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update const handleSave = () => { save(); }; - const TokenPlacementIcon = forwardRef((props, ref) => { - return ( -
- {tokenPlacement == 'url' ? 'URL' : 'Headers'} - -
- ); - }); - - const CredentialsPlacementIcon = forwardRef((props, ref) => { - return ( -
- {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} - -
- ); - }); - const handleChange = (key, value) => { dispatch( updateAuth({ @@ -84,6 +65,7 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update refreshTokenUrl, autoRefreshToken, autoFetchToken, + tokenSource, additionalParameters, [key]: value } @@ -130,26 +112,19 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('credentialsPlacement', 'body'); - }} - > - Request Body + handleChange('credentialsPlacement', 'body') }, + { id: 'basic_auth_header', label: 'Basic Auth Header', onClick: () => handleChange('credentialsPlacement', 'basic_auth_header') } + ]} + selectedItemId={credentialsPlacement} + placement="bottom-end" + > +
+ {credentialsPlacement == 'body' ? 'Request Body' : 'Basic Auth Header'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('credentialsPlacement', 'basic_auth_header'); - }} - > - Basic Auth Header -
- +
@@ -160,6 +135,24 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update Token
+
+ +
+ handleChange('tokenSource', 'access_token') }, + { id: 'id_token', label: 'ID Token', onClick: () => handleChange('tokenSource', 'id_token') } + ]} + selectedItemId={tokenSource} + placement="bottom-end" + > +
+ {tokenSource === 'id_token' ? 'ID Token' : 'Access Token'} + +
+
+
+
@@ -178,26 +171,19 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update
- } placement="bottom-end"> -
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'header'); - }} - > - Header + handleChange('tokenPlacement', 'header') }, + { id: 'url', label: 'URL', onClick: () => handleChange('tokenPlacement', 'url') } + ]} + selectedItemId={tokenPlacement} + placement="bottom-end" + > +
+ {tokenPlacement == 'url' ? 'URL' : 'Headers'} +
-
{ - dropdownTippyRef.current.hide(); - handleChange('tokenPlacement', 'url'); - }} - > - URL -
- +
{ diff --git a/packages/bruno-converters/package.json b/packages/bruno-converters/package.json index 326bbc97e..0753c4150 100644 --- a/packages/bruno-converters/package.json +++ b/packages/bruno-converters/package.json @@ -28,7 +28,7 @@ "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.4", - "@opencollection/types": "~0.5.0", + "@opencollection/types": "~0.8.0", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-commonjs": "^23.0.2", "@rollup/plugin-node-resolve": "^15.0.1", diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 0942ac374..1cadc8de0 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -160,7 +160,7 @@ const configureRequest = async ( if (request.oauth2) { let requestCopy = cloneDeep(request); - const { oauth2: { grantType, tokenPlacement, tokenHeaderPrefix, tokenQueryKey, accessTokenUrl, refreshTokenUrl } = {}, collectionVariables, folderVariables, requestVariables } = requestCopy || {}; + const { oauth2: { grantType, tokenPlacement, tokenHeaderPrefix, tokenQueryKey, tokenSource, accessTokenUrl, refreshTokenUrl } = {}, collectionVariables, folderVariables, requestVariables } = requestCopy || {}; // Get cert/proxy configs for token and refresh URLs let certsAndProxyConfigForTokenUrl = certsAndProxyConfig; @@ -221,56 +221,68 @@ const configureRequest = async ( interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars, promptVariables); ({ credentials, url: oauth2Url, credentialsId, debugInfo } = await getOAuth2TokenUsingAuthorizationCode({ request: requestCopy, collectionUid, certsAndProxyConfigForTokenUrl, certsAndProxyConfigForRefreshUrl })); request.oauth2Credentials = { credentials, url: oauth2Url, collectionUid, credentialsId, debugInfo, folderUid: request.oauth2Credentials?.folderUid }; - if (tokenPlacement == 'header' && credentials?.access_token) { - request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials.access_token}`.trim(); - } else { - try { - const url = new URL(request.url); - url?.searchParams?.set(tokenQueryKey, credentials?.access_token); - request.url = url?.toString(); - } catch (error) {} + { + const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token; + if (tokenPlacement == 'header' && tokenValue) { + request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim(); + } else if (tokenValue) { + try { + const url = new URL(request.url); + url.searchParams.set(tokenQueryKey, tokenValue); + request.url = url.toString(); + } catch (error) {} + } } break; case 'implicit': interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars, promptVariables); ({ credentials, url: oauth2Url, credentialsId, debugInfo } = await getOAuth2TokenUsingImplicitGrant({ request: requestCopy, collectionUid })); request.oauth2Credentials = { credentials, url: oauth2Url, collectionUid, credentialsId, debugInfo, folderUid: request.oauth2Credentials?.folderUid }; - if (tokenPlacement == 'header') { - request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`; - } else { - try { - const url = new URL(request.url); - url?.searchParams?.set(tokenQueryKey, credentials?.access_token); - request.url = url?.toString(); - } catch (error) {} + { + const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token; + if (tokenPlacement == 'header' && tokenValue) { + request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim(); + } else if (tokenValue) { + try { + const url = new URL(request.url); + url.searchParams.set(tokenQueryKey, tokenValue); + request.url = url.toString(); + } catch (error) {} + } } break; case 'client_credentials': interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars, promptVariables); ({ credentials, url: oauth2Url, credentialsId, debugInfo } = await getOAuth2TokenUsingClientCredentials({ request: requestCopy, collectionUid, certsAndProxyConfigForTokenUrl, certsAndProxyConfigForRefreshUrl })); request.oauth2Credentials = { credentials, url: oauth2Url, collectionUid, credentialsId, debugInfo, folderUid: request.oauth2Credentials?.folderUid }; - if (tokenPlacement == 'header' && credentials?.access_token) { - request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials.access_token}`.trim(); - } else { - try { - const url = new URL(request.url); - url?.searchParams?.set(tokenQueryKey, credentials?.access_token); - request.url = url?.toString(); - } catch (error) {} + { + const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token; + if (tokenPlacement == 'header' && tokenValue) { + request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim(); + } else if (tokenValue) { + try { + const url = new URL(request.url); + url.searchParams.set(tokenQueryKey, tokenValue); + request.url = url.toString(); + } catch (error) {} + } } break; case 'password': interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars, promptVariables); ({ credentials, url: oauth2Url, credentialsId, debugInfo } = await getOAuth2TokenUsingPasswordCredentials({ request: requestCopy, collectionUid, certsAndProxyConfigForTokenUrl, certsAndProxyConfigForRefreshUrl })); request.oauth2Credentials = { credentials, url: oauth2Url, collectionUid, credentialsId, debugInfo, folderUid: request.oauth2Credentials?.folderUid }; - if (tokenPlacement == 'header' && credentials?.access_token) { - request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials.access_token}`.trim(); - } else { - try { - const url = new URL(request.url); - url?.searchParams?.set(tokenQueryKey, credentials?.access_token); - request.url = url?.toString(); - } catch (error) {} + { + const tokenValue = tokenSource === 'id_token' ? credentials?.id_token : credentials?.access_token; + if (tokenPlacement == 'header' && tokenValue) { + request.headers['Authorization'] = `${tokenHeaderPrefix} ${tokenValue}`.trim(); + } else if (tokenValue) { + try { + const url = new URL(request.url); + url.searchParams.set(tokenQueryKey, tokenValue); + request.url = url.toString(); + } catch (error) {} + } } break; } diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 2990f9530..7172b1454 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -89,6 +89,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(collectionAuth, 'oauth2.tokenPlacement'), tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), + tokenSource: get(collectionAuth, 'oauth2.tokenSource'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), additionalParameters: get(collectionAuth, 'oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) @@ -111,6 +112,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(collectionAuth, 'oauth2.tokenPlacement'), tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), + tokenSource: get(collectionAuth, 'oauth2.tokenSource'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), additionalParameters: get(collectionAuth, 'oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) @@ -128,6 +130,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(collectionAuth, 'oauth2.tokenPlacement'), tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), + tokenSource: get(collectionAuth, 'oauth2.tokenSource'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), additionalParameters: get(collectionAuth, 'oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; @@ -145,6 +148,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(collectionAuth, 'oauth2.tokenPlacement'), tokenHeaderPrefix: get(collectionAuth, 'oauth2.tokenHeaderPrefix'), tokenQueryKey: get(collectionAuth, 'oauth2.tokenQueryKey'), + tokenSource: get(collectionAuth, 'oauth2.tokenSource'), autoFetchToken: get(collectionAuth, 'oauth2.autoFetchToken'), autoRefreshToken: get(collectionAuth, 'oauth2.autoRefreshToken'), additionalParameters: get(collectionAuth, 'oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) @@ -206,6 +210,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(request, 'auth.oauth2.tokenPlacement'), tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), + tokenSource: get(request, 'auth.oauth2.tokenSource'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken'), additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) @@ -228,6 +233,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(request, 'auth.oauth2.tokenPlacement'), tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), + tokenSource: get(request, 'auth.oauth2.tokenSource'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken'), additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) @@ -245,6 +251,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(request, 'auth.oauth2.tokenPlacement'), tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), + tokenSource: get(request, 'auth.oauth2.tokenSource'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) }; @@ -262,6 +269,7 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { tokenPlacement: get(request, 'auth.oauth2.tokenPlacement'), tokenHeaderPrefix: get(request, 'auth.oauth2.tokenHeaderPrefix'), tokenQueryKey: get(request, 'auth.oauth2.tokenQueryKey'), + tokenSource: get(request, 'auth.oauth2.tokenSource'), autoFetchToken: get(request, 'auth.oauth2.autoFetchToken'), autoRefreshToken: get(request, 'auth.oauth2.autoRefreshToken'), additionalParameters: get(request, 'auth.oauth2.additionalParameters', { authorization: [], token: [], refresh: [] }) diff --git a/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts b/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts index fd005b47a..9be961e27 100644 --- a/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts +++ b/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts @@ -114,6 +114,8 @@ const buildTokenConfig = (oauth: BrunoOAuth2): OAuth2TokenConfig | undefined => }; } + tokenConfig.source = oauth.tokenSource || 'access_token'; + return Object.keys(tokenConfig).length > 0 ? tokenConfig : undefined; }; @@ -345,6 +347,7 @@ export const toBrunoOAuth2 = (oauth: AuthOAuth2 | null | undefined): BrunoOAuth2 tokenPlacement: null, tokenHeaderPrefix: null, tokenQueryKey: null, + tokenSource: 'access_token', refreshTokenUrl: null, autoRefreshToken: false, // Default to false autoFetchToken: true, // Default to true @@ -363,6 +366,7 @@ export const toBrunoOAuth2 = (oauth: AuthOAuth2 | null | undefined): BrunoOAuth2 // token config if (oauth.tokenConfig?.id) brunoOAuth.credentialsId = oauth.tokenConfig.id; + if (oauth.tokenConfig?.source) brunoOAuth.tokenSource = oauth.tokenConfig.source || 'access_token'; if (oauth.tokenConfig?.placement) { if ('header' in oauth.tokenConfig.placement) { brunoOAuth.tokenPlacement = 'header'; @@ -408,6 +412,7 @@ export const toBrunoOAuth2 = (oauth: AuthOAuth2 | null | undefined): BrunoOAuth2 // token config if (oauth.tokenConfig?.id) brunoOAuth.credentialsId = oauth.tokenConfig.id; + if (oauth.tokenConfig?.source) brunoOAuth.tokenSource = oauth.tokenConfig.source || 'access_token'; if (oauth.tokenConfig?.placement) { if ('header' in oauth.tokenConfig.placement) { brunoOAuth.tokenPlacement = 'header'; @@ -454,6 +459,7 @@ export const toBrunoOAuth2 = (oauth: AuthOAuth2 | null | undefined): BrunoOAuth2 // token config if (oauth.tokenConfig?.id) brunoOAuth.credentialsId = oauth.tokenConfig.id; + if (oauth.tokenConfig?.source) brunoOAuth.tokenSource = oauth.tokenConfig.source || 'access_token'; if (oauth.tokenConfig?.placement) { if ('header' in oauth.tokenConfig.placement) { brunoOAuth.tokenPlacement = 'header'; @@ -502,6 +508,7 @@ export const toBrunoOAuth2 = (oauth: AuthOAuth2 | null | undefined): BrunoOAuth2 // token config if (oauth.tokenConfig?.id) brunoOAuth.credentialsId = oauth.tokenConfig.id; + if (oauth.tokenConfig?.source) brunoOAuth.tokenSource = oauth.tokenConfig.source || 'access_token'; if (oauth.tokenConfig?.placement) { if ('header' in oauth.tokenConfig.placement) { brunoOAuth.tokenPlacement = 'header'; diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 0538cc048..710197e39 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -731,6 +731,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { const tokenQueryKeyKey = _.find(auth, { name: 'token_query_key' }); const autoFetchTokenKey = _.find(auth, { name: 'auto_fetch_token' }); const autoRefreshTokenKey = _.find(auth, { name: 'auto_refresh_token' }); + const tokenSourceKey = _.find(auth, { name: 'token_source' }); return { auth: { oauth2: @@ -746,6 +747,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { scope: scopeKey ? scopeKey.value : '', credentialsPlacement: credentialsPlacementKey?.value ? credentialsPlacementKey.value : 'body', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', @@ -766,6 +768,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { pkce: pkceKey ? safeParseJson(pkceKey?.value) ?? false : false, credentialsPlacement: credentialsPlacementKey?.value ? credentialsPlacementKey.value : 'body', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', @@ -782,6 +785,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { scope: scopeKey ? scopeKey.value : '', credentialsPlacement: credentialsPlacementKey?.value ? credentialsPlacementKey.value : 'body', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', @@ -797,6 +801,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { scope: scopeKey ? scopeKey.value : '', state: stateKey ? stateKey.value : '', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index 8fe6eced4..2c4ec492a 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -344,6 +344,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { const tokenQueryKeyKey = _.find(auth, { name: 'token_query_key' }); const autoFetchTokenKey = _.find(auth, { name: 'auto_fetch_token' }); const autoRefreshTokenKey = _.find(auth, { name: 'auto_refresh_token' }); + const tokenSourceKey = _.find(auth, { name: 'token_source' }); return { auth: { oauth2: @@ -359,6 +360,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { scope: scopeKey ? scopeKey.value : '', credentialsPlacement: credentialsPlacementKey?.value ? credentialsPlacementKey.value : 'body', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', @@ -379,6 +381,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { pkce: pkceKey ? safeParseJson(pkceKey?.value) ?? false : false, credentialsPlacement: credentialsPlacementKey?.value ? credentialsPlacementKey.value : 'body', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', @@ -394,6 +397,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { scope: scopeKey ? scopeKey.value : '', state: stateKey ? stateKey.value : '', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', @@ -409,6 +413,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { scope: scopeKey ? scopeKey.value : '', credentialsPlacement: credentialsPlacementKey?.value ? credentialsPlacementKey.value : 'body', credentialsId: credentialsIdKey?.value ? credentialsIdKey.value : 'credentials', + tokenSource: tokenSourceKey?.value ? tokenSourceKey.value : 'access_token', tokenPlacement: tokenPlacementKey?.value ? tokenPlacementKey.value : 'header', tokenHeaderPrefix: tokenHeaderPrefixKey?.value ? tokenHeaderPrefixKey.value : '', tokenQueryKey: tokenQueryKeyKey?.value ? tokenQueryKeyKey.value : 'access_token', diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index 420ca90d7..3add8aff2 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -268,6 +268,7 @@ ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ @@ -293,6 +294,7 @@ ${indentString(`state: ${auth?.oauth2?.state || ''}`)} ${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)} ${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ @@ -314,6 +316,7 @@ ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ @@ -334,6 +337,7 @@ ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`state: ${auth?.oauth2?.state || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js index cc5428996..41301cc52 100644 --- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -157,6 +157,7 @@ ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ @@ -182,6 +183,7 @@ ${indentString(`state: ${auth?.oauth2?.state || ''}`)} ${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)} ${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ @@ -202,6 +204,7 @@ ${indentString(`client_id: ${auth?.oauth2?.clientId || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`state: ${auth?.oauth2?.state || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ @@ -222,6 +225,7 @@ ${indentString(`client_secret: ${auth?.oauth2?.clientSecret || ''}`)} ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)} ${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)} ${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)} +${indentString(`token_source: ${auth?.oauth2?.tokenSource || 'access_token'}`)} ${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${ auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : '' }${ diff --git a/packages/bruno-lang/v2/tests/examples/fixtures/bru/oauth2-examples.bru b/packages/bruno-lang/v2/tests/examples/fixtures/bru/oauth2-examples.bru index 1b0e77097..b88aeb3eb 100644 --- a/packages/bruno-lang/v2/tests/examples/fixtures/bru/oauth2-examples.bru +++ b/packages/bruno-lang/v2/tests/examples/fixtures/bru/oauth2-examples.bru @@ -27,6 +27,7 @@ auth:oauth2 { pkce: true credentials_placement: header credentials_id: authorization + token_source: access_token token_placement: header token_header_prefix: Bearer auto_fetch_token: true diff --git a/packages/bruno-lang/v2/tests/examples/fixtures/json/oauth2-examples.json b/packages/bruno-lang/v2/tests/examples/fixtures/json/oauth2-examples.json index 9b625908a..58fbade63 100644 --- a/packages/bruno-lang/v2/tests/examples/fixtures/json/oauth2-examples.json +++ b/packages/bruno-lang/v2/tests/examples/fixtures/json/oauth2-examples.json @@ -31,6 +31,7 @@ "pkce": true, "credentialsPlacement": "header", "credentialsId": "authorization", + "tokenSource": "access_token", "tokenPlacement": "header", "tokenHeaderPrefix": "Bearer", "tokenQueryKey": "access_token", diff --git a/packages/bruno-lang/v2/tests/fixtures/request.bru b/packages/bruno-lang/v2/tests/fixtures/request.bru index c10982f6e..3bb33bb15 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.bru +++ b/packages/bruno-lang/v2/tests/fixtures/request.bru @@ -81,6 +81,7 @@ auth:oauth2 { pkce: false credentials_placement: body credentials_id: credentials + token_source: access_token token_placement: header token_header_prefix: Bearer auto_fetch_token: true diff --git a/packages/bruno-lang/v2/tests/fixtures/request.json b/packages/bruno-lang/v2/tests/fixtures/request.json index 86cb48e5d..bc5218ece 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.json +++ b/packages/bruno-lang/v2/tests/fixtures/request.json @@ -141,6 +141,7 @@ "clientId": "client_id_1", "clientSecret": "client_secret_1", "credentialsId": "credentials", + "tokenSource": "access_token", "credentialsPlacement": "body", "grantType": "authorization_code", "pkce": false, diff --git a/packages/bruno-requests/src/auth/oauth2-helper.ts b/packages/bruno-requests/src/auth/oauth2-helper.ts index d398694ce..de37e43ee 100644 --- a/packages/bruno-requests/src/auth/oauth2-helper.ts +++ b/packages/bruno-requests/src/auth/oauth2-helper.ts @@ -27,6 +27,7 @@ export interface OAuth2Config { credentialsId?: string; autoRefreshToken?: boolean; autoFetchToken?: boolean; + tokenSource?: 'access_token' | 'id_token'; additionalParameters?: { token?: AdditionalParameter[]; }; @@ -320,7 +321,8 @@ export const getOAuth2Token = async (oauth2Config: OAuth2Config, tokenStore: Tok grantType, accessTokenUrl, credentialsId = 'default', - autoFetchToken = true + autoFetchToken = true, + tokenSource = 'access_token' } = oauth2Config; if (verbose) { @@ -346,7 +348,7 @@ export const getOAuth2Token = async (oauth2Config: OAuth2Config, tokenStore: Tok // Check if token is expired if (!isTokenExpired(existingToken)) { // Token is valid, use it - return existingToken.access_token; + return tokenSource === 'id_token' ? existingToken.id_token : existingToken.access_token; } else { // Token is expired if (autoFetchToken) { @@ -354,7 +356,7 @@ export const getOAuth2Token = async (oauth2Config: OAuth2Config, tokenStore: Tok await tokenStore.deleteCredential({ url: accessTokenUrl, credentialsId }); } else { // Return expired token if autoFetchToken is disabled - return existingToken.access_token; + return tokenSource === 'id_token' ? existingToken.id_token : existingToken.access_token; } } } else { @@ -393,5 +395,5 @@ export const getOAuth2Token = async (oauth2Config: OAuth2Config, tokenStore: Tok console.warn('OAuth2: Failed to save token to store, but proceeding with token'); } - return tokenResponse.access_token; + return tokenSource === 'id_token' ? tokenResponse.id_token : tokenResponse.access_token; }; diff --git a/packages/bruno-schema-types/src/common/auth.ts b/packages/bruno-schema-types/src/common/auth.ts index b620d64b3..c8a31499b 100644 --- a/packages/bruno-schema-types/src/common/auth.ts +++ b/packages/bruno-schema-types/src/common/auth.ts @@ -77,6 +77,7 @@ export interface OAuth2 { refreshTokenUrl?: string | null; autoRefreshToken?: boolean | null; autoFetchToken?: boolean | null; + tokenSource?: 'access_token' | 'id_token'; additionalParameters?: OAuthAdditionalParameters | null; } diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 92787067c..a2f35abb9 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -285,6 +285,11 @@ const oauth2Schema = Yup.object({ then: Yup.string().nullable(), otherwise: Yup.string().nullable().strip() }), + tokenSource: Yup.string().when('grantType', { + is: (val) => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val), + then: Yup.string().oneOf(['access_token', 'id_token']).optional(), + otherwise: Yup.string().optional().strip() + }), tokenPlacement: Yup.string().when('grantType', { is: (val) => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val), then: Yup.string().nullable(),