From f629c3dd2058a57948bf25e953121422454378d2 Mon Sep 17 00:00:00 2001 From: rajashreehj-bruno Date: Fri, 5 Jun 2026 17:31:17 +0530 Subject: [PATCH] fix/3112 - Postman import: OAuth2 Implicit Grant Type Silently Converted to Client Credentials on Import (#8113) * fix/3112 - Postman import: OAuth2 Implicit Grant Type Silently Converted to Client Credentials on Import * fix/3112: Postman import: OAuth2 Implicit Grant Type Silently Converted to Client Credentials on Import * fix/3112 - Postman import: OAuth2 Implicit Grant Type Silently Converted to Client Credentials on Import * fix/3112 * Implicit grant type * Oauth2 implicit grant type test case --- .../Auth/OAuth2/GrantTypeSelector/index.js | 1 + .../src/postman/postman-to-bruno.js | 10 ++- .../postman-to-bruno/process-auth.spec.js | 34 ++++++++++ ...man-import-oauth2-implicit-grant-type.json | 52 +++++++++++++++ .../import-oauth2-implicit-grant-type.spec.ts | 63 +++++++++++++++++++ tests/utils/page/locators.ts | 3 + 6 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 tests/import/postman/fixtures/postman-import-oauth2-implicit-grant-type.json create mode 100644 tests/import/postman/import-oauth2-implicit-grant-type.spec.ts 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 d6417f747..4fd58dfa4 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 @@ -80,6 +80,7 @@ const GrantTypeSelector = ({ item = {}, request, updateAuth, collection }) => { { id: 'implicit', label: 'Implicit', onClick: () => onGrantTypeChange('implicit') }, { id: 'client_credentials', label: 'Client Credentials', onClick: () => onGrantTypeChange('client_credentials') } ]} + data-testid="grant-type-dropdown" selectedItemId={oAuth?.grantType} placement="bottom-end" > diff --git a/packages/bruno-converters/src/postman/postman-to-bruno.js b/packages/bruno-converters/src/postman/postman-to-bruno.js index 67cae27fc..1e3c7b001 100644 --- a/packages/bruno-converters/src/postman/postman-to-bruno.js +++ b/packages/bruno-converters/src/postman/postman-to-bruno.js @@ -308,7 +308,8 @@ export const processAuth = (auth, requestObject, isCollection = false) => { authorization_code_with_pkce: 'authorization_code', authorization_code: 'authorization_code', client_credentials: 'client_credentials', - password_credentials: 'password' + password_credentials: 'password', + implicit: 'implicit' }; const postmanGrantType = findValueUsingKey('grant_type'); @@ -354,6 +355,13 @@ export const processAuth = (auth, requestObject, isCollection = false) => { case 'client_credentials': requestObject.auth.oauth2 = baseOAuth2Config; break; + case 'implicit': + requestObject.auth.oauth2 = { + ...baseOAuth2Config, + authorizationUrl: findValueUsingKey('authUrl'), + callbackUrl: findValueUsingKey('redirect_uri') + }; + break; default: console.warn('Unexpected OAuth2 grant type after mapping:', targetGrantType); requestObject.auth.oauth2 = baseOAuth2Config; // Fallback to default which is Client Credentials diff --git a/packages/bruno-converters/tests/postman/postman-to-bruno/process-auth.spec.js b/packages/bruno-converters/tests/postman/postman-to-bruno/process-auth.spec.js index d59116f2e..cd04fd952 100644 --- a/packages/bruno-converters/tests/postman/postman-to-bruno/process-auth.spec.js +++ b/packages/bruno-converters/tests/postman/postman-to-bruno/process-auth.spec.js @@ -420,6 +420,40 @@ describe('processAuth', () => { }); }); + it('should handle oauth2 auth with implicit grant type', () => { + const auth = { + type: 'oauth2', + oauth2: { + grant_type: 'implicit', + authUrl: 'https://auth.example.com', + redirect_uri: 'https://callback.example.com', + accessTokenUrl: 'https://token.example.com', + refreshTokenUrl: 'https://refresh.example.com', + clientId: 'test-client-id', + clientSecret: 'test-client-secret', + scope: 'test-scope', + state: 'test-state', + addTokenTo: 'header', + client_authentication: 'body' + } + }; + processAuth(auth, requestObject); + expect(requestObject.auth.mode).toBe('oauth2'); + expect(requestObject.auth.oauth2).toEqual({ + grantType: 'implicit', + authorizationUrl: 'https://auth.example.com', + callbackUrl: 'https://callback.example.com', + accessTokenUrl: 'https://token.example.com', + refreshTokenUrl: 'https://refresh.example.com', + clientId: 'test-client-id', + clientSecret: 'test-client-secret', + scope: 'test-scope', + state: 'test-state', + tokenPlacement: 'header', + credentialsPlacement: 'body' + }); + }); + it('should handle auth object with undefined type', () => { const auth = {}; processAuth(auth, requestObject); diff --git a/tests/import/postman/fixtures/postman-import-oauth2-implicit-grant-type.json b/tests/import/postman/fixtures/postman-import-oauth2-implicit-grant-type.json new file mode 100644 index 000000000..8b9d4591a --- /dev/null +++ b/tests/import/postman/fixtures/postman-import-oauth2-implicit-grant-type.json @@ -0,0 +1,52 @@ +{ + "info": { + "_postman_id": "fdc5dd4a-4ea5-4c6b-932c-c766e05029d1", + "name": "My Collection", + "description": "### Welcome to Postman! This is your first collection. \n\nCollections are your starting point for building and testing APIs. You can use this one to:\n\n• Group related requests\n• Test your API in real-world scenarios\n• Document and share your requests\n\nUpdate the name and overview whenever you’re ready to make it yours.\n\n[Learn more about Postman Collections.](https://learning.postman.com/docs/collections/collections-overview/)", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "55235588", + "_collection_link": "https://go.postman.co/collection/55235588-fdc5dd4a-4ea5-4c6b-932c-c766e05029d1?source=collection_link" + }, + "item": [ + { + "name": "OAuth2 Implicit Grant Type", + "request": { + "auth": { + "type": "oauth2", + "oauth2": [ + { + "key": "grant_type", + "value": "implicit", + "type": "string" + }, + { + "key": "headerPrefix", + "value": "Bearer", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://api.com/users?X-API-KEY=12345", + "protocol": "https", + "host": [ + "api", + "com" + ], + "path": [ + "users" + ], + "query": [ + { + "key": "X-API-KEY", + "value": "12345" + } + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/tests/import/postman/import-oauth2-implicit-grant-type.spec.ts b/tests/import/postman/import-oauth2-implicit-grant-type.spec.ts new file mode 100644 index 000000000..d0f9183ab --- /dev/null +++ b/tests/import/postman/import-oauth2-implicit-grant-type.spec.ts @@ -0,0 +1,63 @@ +import { test, expect } from '../../../playwright'; +import * as path from 'path'; +import { closeAllCollections, openCollection, selectRequestPaneTab } from '../../utils/page'; +import { buildCommonLocators } from '../../utils/page/locators'; + +test.describe('Import Postman Collection with OAuth2.0 Implicit Grant Type', () => { + let originalShowOpenDialog; + + test.beforeAll(async ({ electronApp }) => { + await electronApp.evaluate(({ dialog }) => { + originalShowOpenDialog = dialog.showOpenDialog; + }); + }); + + test.afterAll(async ({ electronApp, page }) => { + await closeAllCollections(page); + await electronApp.evaluate(({ dialog }) => { + dialog.showOpenDialog = originalShowOpenDialog; + }); + }); + + test('should import Postman collection with OAuth2.0 Implicit Grant Type successfully', async ({ page, electronApp, createTmpDir }) => { + const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-import-oauth2-implicit-grant-type.json'); + const locators = buildCommonLocators(page); + const importDir = await createTmpDir('imported-collection'); + + await electronApp.evaluate(({ dialog }, { importDir }) => { + dialog.showOpenDialog = async () => ({ + canceled: false, + filePaths: [importDir] + }); + }, { importDir }); + + await test.step('Open import collection modal', async () => { + await locators.plusMenu.button().click(); + await locators.plusMenu.importCollection().click(); + const importModal = locators.import.modal(); + await importModal.waitFor({ state: 'visible' }); + await expect(locators.modal.title('Import Collection')).toBeVisible(); + await locators.import.fileInput().setInputFiles(postmanFile); + await locators.import.locationModal().waitFor({ state: 'visible', timeout: 5000 }); + await expect(locators.modal.title('Import Collection')).toBeVisible(); + await expect(locators.import.locationModal().getByText('My Collection')).toBeVisible(); + const locationModal = locators.import.locationModal(); + await locators.import.browseLink(locationModal).click(); + await locators.import.importButton(locationModal).click(); + await locationModal.waitFor({ state: 'hidden' }); + }); + + await test.step('Open collection and verify request is displayed', async () => { + await openCollection(page, 'My Collection'); + await expect(locators.sidebar.collection('My Collection')).toBeVisible(); + await expect(locators.sidebar.request('OAuth2 Implicit Grant Type')).toBeVisible(); + await locators.sidebar.request('OAuth2 Implicit Grant Type').click(); + await expect(locators.request.pane()).toBeVisible(); + }); + + await test.step('Verify OAuth2.0 Implicit Grant Type is set correctly', async () => { + await selectRequestPaneTab(page, 'Auth'); + await expect(locators.auth.oauth2.grantTypeDropdown()).toContainText('Implicit'); + }); + }); +}); diff --git a/tests/utils/page/locators.ts b/tests/utils/page/locators.ts index 7a2d4c4c1..efd432a05 100644 --- a/tests/utils/page/locators.ts +++ b/tests/utils/page/locators.ts @@ -94,6 +94,9 @@ export const buildCommonLocators = (page: Page) => ({ apiKey: { placementSelector: () => page.getByTestId('auth-placement-selector'), placementLabel: () => page.getByTestId('auth-placement-label') + }, + oauth2: { + grantTypeDropdown: () => page.getByTestId('grant-type-dropdown') } }, tags: {