From 87f9cbf6fb5c86cc3b9d30c6f6e99b5d02d624d7 Mon Sep 17 00:00:00 2001 From: Ugonna Akali <137432604+Ugonnaak1@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:48:24 -0700 Subject: [PATCH 01/12] Surface Errors from MsalRuntime with Interaction Required (#7961) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When customers use `acquireTokenSilent` with msal-node-runtime, errors reported to OneAuth-MSAL (such as interaction_required) are surfaced as: ```   "errormessage": "interaction_required: (pii)",   "errorname": "InteractionRequiredAuthError",   "errorstack": "InteractionRequiredAuthError: interaction_required: (pii)\n at ue.wrapError (c:\\Program VS :2:386244)\n at Object.o (c:\\Program VS :2:381487)" ``` However, these errors lack critical context such as the error code and error tag from the broker or our library which makes it difficult for our team to diagnose and resolve their issues. This PR helps surface errors for interaction-required scenarios by replacing `InteractionRequiredAuthError` with `NativeAuthError` for InteractionRequired Status in NativeBrokerPlugin and enhancing the NativeAuthError context --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ...-9b2b5205-8f2c-49f3-bf7e-b00665abef87.json | 7 +++++++ .../src/broker/NativeBrokerPlugin.ts | 7 +++++-- .../test/broker/NativeBrokerPlugin.spec.ts | 20 +++++++------------ 3 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 change/@azure-msal-node-extensions-9b2b5205-8f2c-49f3-bf7e-b00665abef87.json diff --git a/change/@azure-msal-node-extensions-9b2b5205-8f2c-49f3-bf7e-b00665abef87.json b/change/@azure-msal-node-extensions-9b2b5205-8f2c-49f3-bf7e-b00665abef87.json new file mode 100644 index 0000000000..e417f812b7 --- /dev/null +++ b/change/@azure-msal-node-extensions-9b2b5205-8f2c-49f3-bf7e-b00665abef87.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Surface Errors from MsalRuntime with Interaction Required #7961", + "packageName": "@azure/msal-node-extensions", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts index b00e0a6ee9..d05016aabc 100644 --- a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts +++ b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts @@ -647,12 +647,15 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { ) { const { errorCode, errorStatus, errorContext, errorTag } = error as MsalRuntimeError; + const enhancedErrorContext = errorContext + ? `${errorContext} (Error Code: ${errorCode}, Tag: ${errorTag})` + : `(Error Code: ${errorCode}, Tag: ${errorTag})`; switch (errorStatus) { case ErrorStatus.InteractionRequired: case ErrorStatus.AccountUnusable: return new InteractionRequiredAuthError( ErrorCodes.INTERATION_REQUIRED_ERROR_CODE, - errorContext + enhancedErrorContext ); case ErrorStatus.NoNetwork: case ErrorStatus.NetworkTemporarilyUnavailable: @@ -682,7 +685,7 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { default: return new NativeAuthError( ErrorStatus[errorStatus], - errorContext, + enhancedErrorContext, errorCode, errorTag ); diff --git a/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts b/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts index 79c2ced173..144575802d 100644 --- a/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts +++ b/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts @@ -1,6 +1,9 @@ jest.mock("@azure/msal-node-runtime", () => { + const actual = jest.requireActual("@azure/msal-node-runtime"); return { + ...actual, msalNodeRuntime: { + ...actual.msalNodeRuntime, SignInSilentlyAsync: jest.fn(), SignInAsync: jest.fn(), AcquireTokenSilentlyAsync: jest.fn(), @@ -20,18 +23,6 @@ jest.mock("@azure/msal-node-runtime", () => { SetAdditionalParameter: jest.fn(), })), }, - ErrorStatus: { - Unexpected: 0, - InteractionRequired: 1, - AccountUnusable: 2, - NoNetwork: 3, - NetworkTemporarilyUnavailable: 4, - ServerTemporarilyUnavailable: 5, - UserCanceled: 6, - AuthorityUntrusted: 7, - UserSwitched: 8, - AccountNotFound: 9, - }, }; }); import { NativeBrokerPlugin } from "../../src/broker/NativeBrokerPlugin"; @@ -94,9 +85,12 @@ function createMockAuthResult( if (process.platform === "win32") { describe("NativeBrokerPlugin", () => { + const enhancedErrorContext = msalRuntimeExampleError.errorContext + ? `${msalRuntimeExampleError.errorContext} (Error Code: ${msalRuntimeExampleError.errorCode}, Tag: ${msalRuntimeExampleError.errorTag})` + : `(Error Code: ${msalRuntimeExampleError.errorCode}, Tag: ${msalRuntimeExampleError.errorTag})`; const testNativeAuthError = new NativeAuthError( ErrorStatus[msalRuntimeExampleError.errorStatus], - msalRuntimeExampleError.errorContext, + enhancedErrorContext, msalRuntimeExampleError.errorCode, msalRuntimeExampleError.errorTag ); From 943a8c89e95787cc537100a562b3a35d7a4c5f4f Mon Sep 17 00:00:00 2001 From: Ugonna Akali <137432604+Ugonnaak1@users.noreply.github.com> Date: Tue, 12 Aug 2025 07:21:46 -0700 Subject: [PATCH 02/12] update msal-node-runtime version (#7979) --- ...e-extensions-9ca3981d-f124-46a7-802a-10be0f64a7e7.json | 7 +++++++ package-lock.json | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 change/@azure-msal-node-extensions-9ca3981d-f124-46a7-802a-10be0f64a7e7.json diff --git a/change/@azure-msal-node-extensions-9ca3981d-f124-46a7-802a-10be0f64a7e7.json b/change/@azure-msal-node-extensions-9ca3981d-f124-46a7-802a-10be0f64a7e7.json new file mode 100644 index 0000000000..cbbfcfc2b4 --- /dev/null +++ b/change/@azure-msal-node-extensions-9ca3981d-f124-46a7-802a-10be0f64a7e7.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Bump msal-node-runtime to v0.19.0", + "packageName": "@azure/msal-node-extensions", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/package-lock.json b/package-lock.json index efc498c6e8..d5d701aedb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3700,10 +3700,18 @@ "link": true }, "node_modules/@azure/msal-node-runtime": { +<<<<<<< HEAD "version": "0.18.2", "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.18.2.tgz", "integrity": "sha512-v45fyBQp80BrjZAeGJXl+qggHcbylQiFBihr0ijO2eniDCW9tz5TZBKYsqzH06VuiRaVG/Sa0Hcn4pjhJqFSTw==", "hasInstallScript": true +======= + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.19.4.tgz", + "integrity": "sha512-v90QdV/VKG6gvHx2bQp82yRCJ8IGG7OOk6gDQgbKvoHtOs7mSEz2CIqWydUpwCryJkUwgNfgMPAMoGhe/a4fOw==", + "hasInstallScript": true, + "license": "MIT" +>>>>>>> ebcfec14b (update msal-node-runtime version (#7979)) }, "node_modules/@azure/msal-react": { "resolved": "lib/msal-react", From 4f2da6d172dbf9deef93e1656a4d57afc4cfc415 Mon Sep 17 00:00:00 2001 From: Ugonna Akali <137432604+Ugonnaak1@users.noreply.github.com> Date: Mon, 25 Aug 2025 16:02:44 -0700 Subject: [PATCH 03/12] Enable passing of redirect uri for Nativebroker (#8005) Current PCA requests don't allow the customer to pass in their own redirecturi. This is an issue for signed MacOS apps because the customer is forced to use the unsigned redirect URI which will hit a redirecturi validation error in the Apple Broker ``` errorMessage: 'Description: Error Domain=MSALErrorDomain Code=-50000 "(null)" UserInfo={MSALErrorDescriptionKey=MSAL redirectUri validation error: redirect uri has incorrect scheme - it must be in the form of msauth.://auth\n' + 'ADAL redirectUri validation error: Source application does not match redirect uri host. Invalid source app., MSALInternalErrorCodeKey=-42000, MSALBrokerVersionKey=5.2508.0}, Domain: MSALErrorDomain.Error was thrown in sourceArea: Broker (Error Code: -42000, Tag: 508638916)', ``` Solution: Make providing a redirecturi optional. If the customer doesn't provide one, we fallback to the default for each platform in broker scenarios For non-broker scenarios, if redirecturi is provided, we warn them it won't be used and use the default Also added a function to convert error tags to their string version to make error lookup quicker. --- ...-118ac835-7803-4e30-81cd-91c4afe6bf9d.json | 7 ++++ ...-bce3798f-5840-4955-a647-70f9009359fc.json | 7 ++++ .../src/broker/NativeBrokerPlugin.ts | 30 ++++++++++++----- .../src/error/NativeAuthError.ts | 5 +-- extensions/msal-node-extensions/src/index.ts | 1 + .../src/utils/StringUtils.ts | 33 +++++++++++++++++++ .../test/broker/NativeBrokerPlugin.spec.ts | 25 +++++++++----- .../test/utils/StringUtils.test.ts | 30 +++++++++++++++++ lib/msal-node/apiReview/msal-node.api.md | 2 +- .../src/client/PublicClientApplication.ts | 11 +++++-- lib/msal-node/src/error/NodeAuthError.ts | 14 ++++++++ .../src/request/InteractiveRequest.ts | 2 +- .../client/PublicClientApplication.spec.ts | 26 +++++++++++++++ 13 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json create mode 100644 change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json create mode 100644 extensions/msal-node-extensions/src/utils/StringUtils.ts create mode 100644 extensions/msal-node-extensions/test/utils/StringUtils.test.ts diff --git a/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json b/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json new file mode 100644 index 0000000000..d6fc58b438 --- /dev/null +++ b/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "enable passing of redirect uri", + "packageName": "@azure/msal-node", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json b/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json new file mode 100644 index 0000000000..bf5495cbdb --- /dev/null +++ b/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "enable passing of redirect uri", + "packageName": "@azure/msal-node-extensions", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts index d05016aabc..473799ad3c 100644 --- a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts +++ b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts @@ -36,6 +36,7 @@ import { LogLevel as MsalRuntimeLogLevel, } from "@azure/msal-node-runtime"; import { ErrorCodes } from "../utils/Constants.js"; +import { StringUtils } from "../utils/StringUtils.js"; import { NativeAuthError } from "../error/NativeAuthError.js"; import { version, name } from "../packageMetadata.js"; @@ -192,10 +193,16 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { request.correlationId ); const platformRequest = request; + if (!platformRequest.redirectUri) { + platformRequest.redirectUri = + this.chooseRedirectUriByPlatform(platformRequest); + this.logger.info( + "NativeBrokerPlugin - No Redirect URI provided, using default", + platformRequest.redirectUri + ); + } const authParams = this.generateRequestParameters(platformRequest); const account = await this.getAccount(platformRequest); - platformRequest.redirectUri = - this.chooseRedirectUriByPlatform(platformRequest); return new Promise( (resolve: (value: AuthenticationResult) => void, reject) => { @@ -250,9 +257,15 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { request.correlationId ); const platformRequest = request; + if (!platformRequest.redirectUri) { + platformRequest.redirectUri = + this.chooseRedirectUriByPlatform(platformRequest); + this.logger.info( + "NativeBrokerPlugin - No Redirect URI provided, using default", + platformRequest.redirectUri + ); + } const authParams = this.generateRequestParameters(platformRequest); - platformRequest.redirectUri = - this.chooseRedirectUriByPlatform(platformRequest); const account = await this.getAccount(platformRequest); const windowHandle = providedWindowHandle || Buffer.from([0]); @@ -462,9 +475,7 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { request.authority ); - authParams.SetRedirectUri( - this.chooseRedirectUriByPlatform(request) - ); + authParams.SetRedirectUri(request.redirectUri); authParams.SetRequestedScopes(request.scopes.join(" ")); if (request.claims) { @@ -647,9 +658,10 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { ) { const { errorCode, errorStatus, errorContext, errorTag } = error as MsalRuntimeError; + const tagString = StringUtils.tagToString(errorTag); const enhancedErrorContext = errorContext - ? `${errorContext} (Error Code: ${errorCode}, Tag: ${errorTag})` - : `(Error Code: ${errorCode}, Tag: ${errorTag})`; + ? `${errorContext} (Error Code: ${errorCode}, Tag: ${tagString})` + : `(Error Code: ${errorCode}, Tag: ${tagString})`; switch (errorStatus) { case ErrorStatus.InteractionRequired: case ErrorStatus.AccountUnusable: diff --git a/extensions/msal-node-extensions/src/error/NativeAuthError.ts b/extensions/msal-node-extensions/src/error/NativeAuthError.ts index 4740cbc1c7..b5949ea259 100644 --- a/extensions/msal-node-extensions/src/error/NativeAuthError.ts +++ b/extensions/msal-node-extensions/src/error/NativeAuthError.ts @@ -4,10 +4,11 @@ */ import { AuthError } from "@azure/msal-common/node"; +import { StringUtils } from "../utils/StringUtils.js"; export class NativeAuthError extends AuthError { public statusCode: number; - public tag: number; + public tag: string; constructor( errorStatus: string, @@ -18,7 +19,7 @@ export class NativeAuthError extends AuthError { super(errorStatus, errorContext); this.name = "NativeAuthError"; this.statusCode = errorCode; - this.tag = errorTag; + this.tag = StringUtils.tagToString(errorTag); Object.setPrototypeOf(this, NativeAuthError.prototype); } } diff --git a/extensions/msal-node-extensions/src/index.ts b/extensions/msal-node-extensions/src/index.ts index cccd6af36b..7ffdba3e49 100644 --- a/extensions/msal-node-extensions/src/index.ts +++ b/extensions/msal-node-extensions/src/index.ts @@ -14,4 +14,5 @@ export { CrossPlatformLockOptions } from "./lock/CrossPlatformLockOptions.js"; export { PersistenceCreator } from "./persistence/PersistenceCreator.js"; export { IPersistenceConfiguration } from "./persistence/IPersistenceConfiguration.js"; export { Environment } from "./utils/Environment.js"; +export { StringUtils } from "./utils/StringUtils.js"; export { NativeBrokerPlugin } from "./broker/NativeBrokerPlugin.js"; diff --git a/extensions/msal-node-extensions/src/utils/StringUtils.ts b/extensions/msal-node-extensions/src/utils/StringUtils.ts new file mode 100644 index 0000000000..43b251b9ad --- /dev/null +++ b/extensions/msal-node-extensions/src/utils/StringUtils.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +export class StringUtils { + /** + * Converts a numeric tag to a string representation + * @param tag - The numeric tag to convert + * @returns The string representation of the tag + */ + static tagToString(tag: number): string { + if (tag === 0) { + return "UNTAG"; + } + + const tagSymbolSpace = + "abcdefghijklmnopqrstuvwxyz0123456789****************************"; + let tagBuffer = "*****"; + + const chars = [ + tagSymbolSpace[(tag >> 24) & 0x3f], + tagSymbolSpace[(tag >> 18) & 0x3f], + tagSymbolSpace[(tag >> 12) & 0x3f], + tagSymbolSpace[(tag >> 6) & 0x3f], + tagSymbolSpace[(tag >> 0) & 0x3f], + ]; + + tagBuffer = chars.join(""); + + return tagBuffer; + } +} diff --git a/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts b/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts index 144575802d..ee9d378dea 100644 --- a/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts +++ b/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts @@ -54,6 +54,7 @@ import { } from "@azure/msal-common"; import { randomUUID } from "crypto"; import { NativeAuthError } from "../../src/error/NativeAuthError"; +import { StringUtils } from "../../src/utils/StringUtils.js"; import { testMsalRuntimeAccount, testAccountInfo, @@ -86,8 +87,16 @@ function createMockAuthResult( if (process.platform === "win32") { describe("NativeBrokerPlugin", () => { const enhancedErrorContext = msalRuntimeExampleError.errorContext - ? `${msalRuntimeExampleError.errorContext} (Error Code: ${msalRuntimeExampleError.errorCode}, Tag: ${msalRuntimeExampleError.errorTag})` - : `(Error Code: ${msalRuntimeExampleError.errorCode}, Tag: ${msalRuntimeExampleError.errorTag})`; + ? `${msalRuntimeExampleError.errorContext} (Error Code: ${ + msalRuntimeExampleError.errorCode + }, Tag: ${StringUtils.tagToString( + msalRuntimeExampleError.errorTag + )})` + : `(Error Code: ${ + msalRuntimeExampleError.errorCode + }, Tag: ${StringUtils.tagToString( + msalRuntimeExampleError.errorTag + )})`; const testNativeAuthError = new NativeAuthError( ErrorStatus[msalRuntimeExampleError.errorStatus], enhancedErrorContext, @@ -671,7 +680,7 @@ if (process.platform === "win32") { scopes: testAuthenticationResult.scopes, correlationId: testCorrelationId, authority: testAuthenticationResult.authority, - redirectUri: TEST_REDIRECTURI, + redirectUri: "", }; const chooseRedirectUriMock = jest.spyOn( @@ -1508,7 +1517,7 @@ if (process.platform === "win32") { scopes: testAuthenticationResult.scopes, correlationId: testCorrelationId, authority: testAuthenticationResult.authority, - redirectUri: TEST_REDIRECTURI, + redirectUri: "", }; const chooseRedirectUriMock = jest.spyOn( @@ -2286,7 +2295,7 @@ if (process.platform === "win32") { scopes: testAuthenticationResult.scopes, correlationId: testCorrelationId, authority: testAuthenticationResult.authority, - redirectUri: TEST_REDIRECTURI, + redirectUri: "", }; const chooseRedirectUriMock = jest.spyOn( @@ -2331,7 +2340,7 @@ if (process.platform === "win32") { scopes: testAuthenticationResult.scopes, correlationId: testCorrelationId, authority: testAuthenticationResult.authority, - redirectUri: TEST_REDIRECTURI, + redirectUri: "", }; const chooseRedirectUriMock = jest.spyOn( @@ -2384,7 +2393,7 @@ if (process.platform === "win32") { scopes: testAuthenticationResult.scopes, correlationId: testCorrelationId, authority: testAuthenticationResult.authority, - redirectUri: TEST_REDIRECTURI, + redirectUri: "", }; const chooseRedirectUriMock = jest.spyOn( @@ -2429,7 +2438,7 @@ if (process.platform === "win32") { scopes: testAuthenticationResult.scopes, correlationId: testCorrelationId, authority: testAuthenticationResult.authority, - redirectUri: TEST_REDIRECTURI, + redirectUri: "", }; const chooseRedirectUriMock = jest.spyOn( diff --git a/extensions/msal-node-extensions/test/utils/StringUtils.test.ts b/extensions/msal-node-extensions/test/utils/StringUtils.test.ts new file mode 100644 index 0000000000..f5d26d6add --- /dev/null +++ b/extensions/msal-node-extensions/test/utils/StringUtils.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { StringUtils } from "../../src/utils/StringUtils.js"; + +describe("StringUtils", () => { + describe("tagToString tests", () => { + it("Returns 'UNTAG' for tag value 0", () => { + expect(StringUtils.tagToString(0)).toBe("UNTAG"); + }); + + it("Converts numeric tag to 5-character string", () => { + const tag = 0x01234567; + const result = StringUtils.tagToString(tag); + + expect(result).toHaveLength(5); + expect(typeof result).toBe("string"); + }); + + it("Produce same results for same input", () => { + const tag = 0x12345678; + const result1 = StringUtils.tagToString(tag); + const result2 = StringUtils.tagToString(tag); + + expect(result1).toBe(result2); + }); + }); +}); diff --git a/lib/msal-node/apiReview/msal-node.api.md b/lib/msal-node/apiReview/msal-node.api.md index e4930d6228..bafa930de4 100644 --- a/lib/msal-node/apiReview/msal-node.api.md +++ b/lib/msal-node/apiReview/msal-node.api.md @@ -250,7 +250,7 @@ export { InteractionRequiredAuthError } export { InteractionRequiredAuthErrorCodes } // @public -export type InteractiveRequest = Partial> & { +export type InteractiveRequest = Partial> & { openBrowser: (url: string) => Promise; scopes?: Array; successTemplate?: string; diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index b46e564eae..4a1106c4f4 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -161,7 +161,7 @@ export class PublicClientApplication ...remainingProperties, clientId: this.config.auth.clientId, scopes: request.scopes || CommonConstants.OIDC_DEFAULT_SCOPES, - redirectUri: `${Constants.HTTP_PROTOCOL}${Constants.LOCALHOST}`, + redirectUri: request.redirectUri || "", authority: request.authority || this.config.auth.authority, correlationId: correlationId, extraParameters: { @@ -177,6 +177,9 @@ export class PublicClientApplication ); } + if (request.redirectUri) { + throw NodeAuthError.createRedirectUriNotSupportedError(); + } const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes(); @@ -257,7 +260,7 @@ export class PublicClientApplication ...request, clientId: this.config.auth.clientId, scopes: request.scopes || CommonConstants.OIDC_DEFAULT_SCOPES, - redirectUri: `${Constants.HTTP_PROTOCOL}${Constants.LOCALHOST}`, + redirectUri: request.redirectUri || "", authority: request.authority || this.config.auth.authority, correlationId: correlationId, extraParameters: { @@ -271,6 +274,10 @@ export class PublicClientApplication return this.nativeBrokerPlugin.acquireTokenSilent(brokerRequest); } + if (request.redirectUri) { + throw NodeAuthError.createRedirectUriNotSupportedError(); + } + return super.acquireTokenSilent(request); } diff --git a/lib/msal-node/src/error/NodeAuthError.ts b/lib/msal-node/src/error/NodeAuthError.ts index c8fd60d054..4cc9af45f3 100644 --- a/lib/msal-node/src/error/NodeAuthError.ts +++ b/lib/msal-node/src/error/NodeAuthError.ts @@ -41,6 +41,10 @@ export const NodeAuthErrorMessage = { code: "thumbprint_missing_from_client_certificate", desc: "Client certificate does not contain a SHA-1 or SHA-256 thumbprint.", }, + redirectUriNotSupported: { + code: "redirect_uri_not_supported", + desc: "RedirectUri is not supported in this scenario. Please remove redirectUri from the request.", + }, }; export class NodeAuthError extends AuthError { @@ -128,4 +132,14 @@ export class NodeAuthError extends AuthError { NodeAuthErrorMessage.thumbprintMissing.desc ); } + + /** + * Creates an error thrown when redirectUri is provided in an unsupported scenario + */ + static createRedirectUriNotSupportedError(): NodeAuthError { + return new NodeAuthError( + NodeAuthErrorMessage.redirectUriNotSupported.code, + NodeAuthErrorMessage.redirectUriNotSupported.desc + ); + } } diff --git a/lib/msal-node/src/request/InteractiveRequest.ts b/lib/msal-node/src/request/InteractiveRequest.ts index 9dbe7debee..3a2e67ada1 100644 --- a/lib/msal-node/src/request/InteractiveRequest.ts +++ b/lib/msal-node/src/request/InteractiveRequest.ts @@ -20,7 +20,7 @@ import { ILoopbackClient } from "../network/ILoopbackClient.js"; export type InteractiveRequest = Partial< Omit< CommonAuthorizationUrlRequest, - "scopes" | "redirectUri" | "storeInCache" + "scopes" | "storeInCache" > > & { openBrowser: (url: string) => Promise; diff --git a/lib/msal-node/test/client/PublicClientApplication.spec.ts b/lib/msal-node/test/client/PublicClientApplication.spec.ts index c8daa86cce..0581ee1763 100644 --- a/lib/msal-node/test/client/PublicClientApplication.spec.ts +++ b/lib/msal-node/test/client/PublicClientApplication.spec.ts @@ -623,6 +623,19 @@ describe("PublicClientApplication", () => { // Catch errors thrown after the function call this test is testing }); }); + + test("acquireTokenSilent throws error when redirectUri is provided", async () => { + const authApp = new PublicClientApplication(appConfig); + const request: SilentFlowRequest = { + scopes: TEST_CONSTANTS.DEFAULT_GRAPH_SCOPE, + account: testAccount, + redirectUri: "http://localhost:3000/redirect", + }; + + await expect(authApp.acquireTokenSilent(request)).rejects.toThrow( + "RedirectUri is not supported in this scenario" + ); + }); }); describe("acquireTokenInteractive tests", () => { @@ -1051,6 +1064,19 @@ describe("PublicClientApplication", () => { done(); }); }); + + test("acquireTokenInteractive throws error when redirectUri is provided", async () => { + const authApp = new PublicClientApplication(appConfig); + const request: InteractiveRequest = { + scopes: TEST_CONSTANTS.DEFAULT_GRAPH_SCOPE, + redirectUri: "http://localhost:3000/redirect", + openBrowser: jest.fn(), + }; + + await expect( + authApp.acquireTokenInteractive(request) + ).rejects.toThrow("RedirectUri is not supported in this scenario"); + }); }); describe("signOut tests", () => { From 88b37348c5749247e318af8f92110608cd9b217f Mon Sep 17 00:00:00 2001 From: Ugonna Akali <137432604+Ugonnaak1@users.noreply.github.com> Date: Tue, 16 Sep 2025 09:26:43 -0700 Subject: [PATCH 04/12] Reset Redirecturi during broker fallback (#8049) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a user attempts a broker flow but the broker isn’t available on their machine, the flow falls back to the browser. However, since a redirect URI was provided for the broker flow, an error is thrown. This PR adds a check to determine whether the broker is enabled in the config and resets the redirect URI to an empty string instead of throwing an error. --- ...-f21ce81f-a941-4847-a7e4-e9ea5b515c40.json | 7 ++ .../src/client/PublicClientApplication.ts | 14 +++- .../client/PublicClientApplication.spec.ts | 82 +++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 change/@azure-msal-node-f21ce81f-a941-4847-a7e4-e9ea5b515c40.json diff --git a/change/@azure-msal-node-f21ce81f-a941-4847-a7e4-e9ea5b515c40.json b/change/@azure-msal-node-f21ce81f-a941-4847-a7e4-e9ea5b515c40.json new file mode 100644 index 0000000000..a8ae4ed173 --- /dev/null +++ b/change/@azure-msal-node-f21ce81f-a941-4847-a7e4-e9ea5b515c40.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "broker redirect uri changes", + "packageName": "@azure/msal-node", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index 4a1106c4f4..352d28f55e 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -178,8 +178,14 @@ export class PublicClientApplication } if (request.redirectUri) { - throw NodeAuthError.createRedirectUriNotSupportedError(); + // If its not a broker fallback scenario, we throw a error + if (!this.config.broker.nativeBrokerPlugin) { + throw NodeAuthError.createRedirectUriNotSupportedError(); + } + // If a redirect URI is provided for a broker flow but MSAL runtime startup failed, we fall back to the browser flow and will ignore the redirect URI provided for the broker flow + request.redirectUri = ""; } + const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes(); @@ -275,7 +281,11 @@ export class PublicClientApplication } if (request.redirectUri) { - throw NodeAuthError.createRedirectUriNotSupportedError(); + // If its not a broker fallback scenario, we throw a error + if (!this.config.broker.nativeBrokerPlugin) { + throw NodeAuthError.createRedirectUriNotSupportedError(); + } + request.redirectUri = ""; } return super.acquireTokenSilent(request); diff --git a/lib/msal-node/test/client/PublicClientApplication.spec.ts b/lib/msal-node/test/client/PublicClientApplication.spec.ts index 0581ee1763..9165c6f995 100644 --- a/lib/msal-node/test/client/PublicClientApplication.spec.ts +++ b/lib/msal-node/test/client/PublicClientApplication.spec.ts @@ -636,6 +636,43 @@ describe("PublicClientApplication", () => { "RedirectUri is not supported in this scenario" ); }); + + test("acquireTokenSilent resets redirectUri when broker fallback occurs", async () => { + // Create a broker plugin with broker unavailable + const mockBrokerPlugin = new MockNativeBrokerPlugin(); + mockBrokerPlugin.isBrokerAvailable = false; + + const authApp = new PublicClientApplication({ + ...appConfig, + broker: { + nativeBrokerPlugin: mockBrokerPlugin, + }, + }); + + const silentFlowClient = getMsalCommonAutoMock().SilentFlowClient; + jest.spyOn(msalCommon, "SilentFlowClient").mockImplementation( + (config) => new silentFlowClient(config) + ); + jest.spyOn( + silentFlowClient.prototype, + "acquireCachedToken" + ).mockResolvedValue([ + mockAuthenticationResult, + CacheOutcome.NOT_APPLICABLE, + ]); + + const request: SilentFlowRequest = { + scopes: TEST_CONSTANTS.DEFAULT_GRAPH_SCOPE, + account: testAccount, + redirectUri: "http://localhost:3000/redirect", + }; + + // This should not throw and should reset redirectUri to empty string and continue with the request + const response = await authApp.acquireTokenSilent(request); + + expect(response).toEqual(mockAuthenticationResult); + expect(request.redirectUri).toBe(""); + }); }); describe("acquireTokenInteractive tests", () => { @@ -1077,6 +1114,51 @@ describe("PublicClientApplication", () => { authApp.acquireTokenInteractive(request) ).rejects.toThrow("RedirectUri is not supported in this scenario"); }); + + test("acquireTokenInteractive resets redirectUri when broker fallback occurs", async () => { + // Create a broker plugin with broker unavailable to simulate fallback scenario + const mockBrokerPlugin = new MockNativeBrokerPlugin(); + mockBrokerPlugin.isBrokerAvailable = false; + + const authApp = new PublicClientApplication({ + ...appConfig, + broker: { + nativeBrokerPlugin: mockBrokerPlugin, + }, + }); + + const request: InteractiveRequest = { + scopes: TEST_CONSTANTS.DEFAULT_GRAPH_SCOPE, + redirectUri: "http://localhost:3000/redirect", + openBrowser: jest.fn(), + }; + + jest.spyOn( + LoopbackClient.prototype, + "listenForAuthCode" + ).mockResolvedValue({ + code: TEST_CONSTANTS.AUTHORIZATION_CODE, + }); + + jest.spyOn( + LoopbackClient.prototype, + "getRedirectUri" + ).mockReturnValue(TEST_CONSTANTS.REDIRECT_URI); + + jest.spyOn(authApp, "acquireTokenByCode").mockResolvedValue( + mockAuthenticationResult + ); + + jest.spyOn(authApp, "getAuthCodeUrl").mockResolvedValue( + TEST_CONSTANTS.AUTH_CODE_URL + ); + + // This should not throw and should reset redirectUri to empty string + const response = await authApp.acquireTokenInteractive(request); + + expect(response).toEqual(mockAuthenticationResult); + expect(request.redirectUri).toBe(""); + }); }); describe("signOut tests", () => { From 8e6fa7ae91c628697e86aa74d24f05064f57fc65 Mon Sep 17 00:00:00 2001 From: Ugonna Akali <137432604+Ugonnaak1@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:05:56 -0700 Subject: [PATCH 05/12] update msal-node-runtime version to 0.20.0 (#8113) --- ...ions-e30dc56d-30d4-45c2-b7a2-bb8d03bff668.json | 7 +++++++ extensions/msal-node-extensions/package.json | 2 +- .../src/broker/NativeBrokerPlugin.ts | 4 ++-- package-lock.json | 15 ++++----------- 4 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 change/@azure-msal-node-extensions-e30dc56d-30d4-45c2-b7a2-bb8d03bff668.json diff --git a/change/@azure-msal-node-extensions-e30dc56d-30d4-45c2-b7a2-bb8d03bff668.json b/change/@azure-msal-node-extensions-e30dc56d-30d4-45c2-b7a2-bb8d03bff668.json new file mode 100644 index 0000000000..a647e73b3d --- /dev/null +++ b/change/@azure-msal-node-extensions-e30dc56d-30d4-45c2-b7a2-bb8d03bff668.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Bump msal-node-runtime to v0.20.0", + "packageName": "@azure/msal-node-extensions", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/extensions/msal-node-extensions/package.json b/extensions/msal-node-extensions/package.json index 1e9f44e645..174625deee 100644 --- a/extensions/msal-node-extensions/package.json +++ b/extensions/msal-node-extensions/package.json @@ -65,7 +65,7 @@ }, "dependencies": { "@azure/msal-common": "16.0.0-alpha.0", - "@azure/msal-node-runtime": "^0.18.1", + "@azure/msal-node-runtime": "^0.20.0", "keytar": "^7.8.0" }, "devDependencies": { diff --git a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts index 473799ad3c..3a98dfabae 100644 --- a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts +++ b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts @@ -198,7 +198,7 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { this.chooseRedirectUriByPlatform(platformRequest); this.logger.info( "NativeBrokerPlugin - No Redirect URI provided, using default", - platformRequest.redirectUri + platformRequest.correlationId ); } const authParams = this.generateRequestParameters(platformRequest); @@ -262,7 +262,7 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { this.chooseRedirectUriByPlatform(platformRequest); this.logger.info( "NativeBrokerPlugin - No Redirect URI provided, using default", - platformRequest.redirectUri + platformRequest.correlationId ); } const authParams = this.generateRequestParameters(platformRequest); diff --git a/package-lock.json b/package-lock.json index d5d701aedb..32cd019083 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,7 @@ "license": "MIT", "dependencies": { "@azure/msal-common": "16.0.0-alpha.0", - "@azure/msal-node-runtime": "^0.18.1", + "@azure/msal-node-runtime": "^0.20.0", "keytar": "^7.8.0" }, "devDependencies": { @@ -3700,18 +3700,11 @@ "link": true }, "node_modules/@azure/msal-node-runtime": { -<<<<<<< HEAD - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.18.2.tgz", - "integrity": "sha512-v45fyBQp80BrjZAeGJXl+qggHcbylQiFBihr0ijO2eniDCW9tz5TZBKYsqzH06VuiRaVG/Sa0Hcn4pjhJqFSTw==", - "hasInstallScript": true -======= - "version": "0.19.4", - "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.19.4.tgz", - "integrity": "sha512-v90QdV/VKG6gvHx2bQp82yRCJ8IGG7OOk6gDQgbKvoHtOs7mSEz2CIqWydUpwCryJkUwgNfgMPAMoGhe/a4fOw==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.20.0.tgz", + "integrity": "sha512-lmCO41fjY2BmPnRMTDEwHmTlYVw5AV+7TiNFHpwVUbt/qZtKv/2tQAlCLISXIeY/xA6COtO++MUmDfB6XdR4LA==", "hasInstallScript": true, "license": "MIT" ->>>>>>> ebcfec14b (update msal-node-runtime version (#7979)) }, "node_modules/@azure/msal-react": { "resolved": "lib/msal-react", From e9126bc4e73922beaa68681ba0eba57bf7058ff5 Mon Sep 17 00:00:00 2001 From: Ugonna Akali <137432604+Ugonnaak1@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:24:18 -0800 Subject: [PATCH 06/12] Handle MsalRuntime Error Surfacing (#8120) Aimed to solve the problem discussed [here:](https://identitydivision.visualstudio.com/DevEx/_git/AuthLibrariesApiReview/pullrequest/20409?path=/MSALJS/%5Bmsal-node%5D%20MsalRuntime/Surface_MsalRuntime_Errors.md) Solution 5 implementation --- ...-fa718400-1f30-4ec0-a922-9ab96a7fe335.json | 7 + ...-05784d6a-75fa-4bbf-adf4-543636d3ae42.json | 7 + docs/errors.md | 3 + .../src/broker/NativeBrokerPlugin.ts | 49 +++-- .../src/error/NativeAuthError.ts | 25 --- extensions/msal-node-extensions/src/index.ts | 1 - .../src/utils/StringUtils.ts | 33 ---- .../test/broker/NativeBrokerPlugin.spec.ts | 167 ++++++++++++++---- .../test/utils/StringUtils.test.ts | 30 ---- lib/msal-common/apiReview/msal-common.api.md | 17 +- lib/msal-common/src/error/AuthError.ts | 6 + .../src/error/ClientAuthErrorCodes.ts | 1 + .../src/error/PlatformBrokerError.ts | 66 +++++++ lib/msal-common/src/exports-common.ts | 1 + 14 files changed, 266 insertions(+), 147 deletions(-) create mode 100644 change/@azure-msal-common-fa718400-1f30-4ec0-a922-9ab96a7fe335.json create mode 100644 change/@azure-msal-node-extensions-05784d6a-75fa-4bbf-adf4-543636d3ae42.json delete mode 100644 extensions/msal-node-extensions/src/error/NativeAuthError.ts delete mode 100644 extensions/msal-node-extensions/src/utils/StringUtils.ts delete mode 100644 extensions/msal-node-extensions/test/utils/StringUtils.test.ts create mode 100644 lib/msal-common/src/error/PlatformBrokerError.ts diff --git a/change/@azure-msal-common-fa718400-1f30-4ec0-a922-9ab96a7fe335.json b/change/@azure-msal-common-fa718400-1f30-4ec0-a922-9ab96a7fe335.json new file mode 100644 index 0000000000..35247871a9 --- /dev/null +++ b/change/@azure-msal-common-fa718400-1f30-4ec0-a922-9ab96a7fe335.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "error surfacing changes", + "packageName": "@azure/msal-common", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@azure-msal-node-extensions-05784d6a-75fa-4bbf-adf4-543636d3ae42.json b/change/@azure-msal-node-extensions-05784d6a-75fa-4bbf-adf4-543636d3ae42.json new file mode 100644 index 0000000000..d2e8780492 --- /dev/null +++ b/change/@azure-msal-node-extensions-05784d6a-75fa-4bbf-adf4-543636d3ae42.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "error surfacing changes", + "packageName": "@azure/msal-node-extensions", + "email": "akaliugonna@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/docs/errors.md b/docs/errors.md index 0923b0e1b0..c4c1bb5c7f 100644 --- a/docs/errors.md +++ b/docs/errors.md @@ -172,6 +172,9 @@ This error occurs when MSAL.js surpasses the allotted storage limit when attempt - The nested app auth bridge is disabled. +### `platform_broker_error` +- An error occurred in the native broker. See the platformBrokerError property for details. + ## Client configuration errors ### `redirect_uri_empty` diff --git a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts index 3a98dfabae..af97819a2b 100644 --- a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts +++ b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts @@ -17,6 +17,7 @@ import { InteractionRequiredAuthError, Logger, LoggerOptions, + PlatformBrokerError, NativeRequest, NativeSignOutRequest, ServerError, @@ -36,8 +37,6 @@ import { LogLevel as MsalRuntimeLogLevel, } from "@azure/msal-node-runtime"; import { ErrorCodes } from "../utils/Constants.js"; -import { StringUtils } from "../utils/StringUtils.js"; -import { NativeAuthError } from "../error/NativeAuthError.js"; import { version, name } from "../packageMetadata.js"; export class NativeBrokerPlugin implements INativeBrokerPlugin { @@ -650,7 +649,7 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { ); } - private wrapError(error: unknown): NativeAuthError | Object | null { + private wrapError(error: unknown): PlatformBrokerError | Object | null { if ( error && typeof error === "object" && @@ -658,50 +657,62 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { ) { const { errorCode, errorStatus, errorContext, errorTag } = error as MsalRuntimeError; - const tagString = StringUtils.tagToString(errorTag); - const enhancedErrorContext = errorContext - ? `${errorContext} (Error Code: ${errorCode}, Tag: ${tagString})` - : `(Error Code: ${errorCode}, Tag: ${tagString})`; + + const msalNodeRuntimeError = new PlatformBrokerError( + ErrorStatus[errorStatus], + errorContext, + errorCode, + errorTag + ); + + let wrappedError; + switch (errorStatus) { case ErrorStatus.InteractionRequired: case ErrorStatus.AccountUnusable: - return new InteractionRequiredAuthError( + wrappedError = new InteractionRequiredAuthError( ErrorCodes.INTERATION_REQUIRED_ERROR_CODE, - enhancedErrorContext + msalNodeRuntimeError.message ); + break; case ErrorStatus.NoNetwork: case ErrorStatus.NetworkTemporarilyUnavailable: - return createClientAuthError( + wrappedError = createClientAuthError( ClientAuthErrorCodes.noNetworkConnectivity ); + break; case ErrorStatus.ServerTemporarilyUnavailable: - return new ServerError( + wrappedError = new ServerError( ErrorCodes.SERVER_UNAVAILABLE, errorContext ); + break; case ErrorStatus.UserCanceled: - return createClientAuthError( + wrappedError = createClientAuthError( ClientAuthErrorCodes.userCanceled ); + break; case ErrorStatus.AuthorityUntrusted: - return createClientConfigurationError( + wrappedError = createClientConfigurationError( ClientConfigurationErrorCodes.untrustedAuthority ); + break; case ErrorStatus.UserSwitched: // Not an error case, if there's customer demand we can surface this as a response property return null; case ErrorStatus.AccountNotFound: - return createClientAuthError( + wrappedError = createClientAuthError( ClientAuthErrorCodes.noAccountFound ); + break; default: - return new NativeAuthError( - ErrorStatus[errorStatus], - enhancedErrorContext, - errorCode, - errorTag + wrappedError = createClientAuthError( + ClientAuthErrorCodes.platformBrokerError ); } + + wrappedError.platformBrokerError = msalNodeRuntimeError; + return wrappedError; } throw error; } diff --git a/extensions/msal-node-extensions/src/error/NativeAuthError.ts b/extensions/msal-node-extensions/src/error/NativeAuthError.ts deleted file mode 100644 index b5949ea259..0000000000 --- a/extensions/msal-node-extensions/src/error/NativeAuthError.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { AuthError } from "@azure/msal-common/node"; -import { StringUtils } from "../utils/StringUtils.js"; - -export class NativeAuthError extends AuthError { - public statusCode: number; - public tag: string; - - constructor( - errorStatus: string, - errorContext: string, - errorCode: number, - errorTag: number - ) { - super(errorStatus, errorContext); - this.name = "NativeAuthError"; - this.statusCode = errorCode; - this.tag = StringUtils.tagToString(errorTag); - Object.setPrototypeOf(this, NativeAuthError.prototype); - } -} diff --git a/extensions/msal-node-extensions/src/index.ts b/extensions/msal-node-extensions/src/index.ts index 7ffdba3e49..cccd6af36b 100644 --- a/extensions/msal-node-extensions/src/index.ts +++ b/extensions/msal-node-extensions/src/index.ts @@ -14,5 +14,4 @@ export { CrossPlatformLockOptions } from "./lock/CrossPlatformLockOptions.js"; export { PersistenceCreator } from "./persistence/PersistenceCreator.js"; export { IPersistenceConfiguration } from "./persistence/IPersistenceConfiguration.js"; export { Environment } from "./utils/Environment.js"; -export { StringUtils } from "./utils/StringUtils.js"; export { NativeBrokerPlugin } from "./broker/NativeBrokerPlugin.js"; diff --git a/extensions/msal-node-extensions/src/utils/StringUtils.ts b/extensions/msal-node-extensions/src/utils/StringUtils.ts deleted file mode 100644 index 43b251b9ad..0000000000 --- a/extensions/msal-node-extensions/src/utils/StringUtils.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -export class StringUtils { - /** - * Converts a numeric tag to a string representation - * @param tag - The numeric tag to convert - * @returns The string representation of the tag - */ - static tagToString(tag: number): string { - if (tag === 0) { - return "UNTAG"; - } - - const tagSymbolSpace = - "abcdefghijklmnopqrstuvwxyz0123456789****************************"; - let tagBuffer = "*****"; - - const chars = [ - tagSymbolSpace[(tag >> 24) & 0x3f], - tagSymbolSpace[(tag >> 18) & 0x3f], - tagSymbolSpace[(tag >> 12) & 0x3f], - tagSymbolSpace[(tag >> 6) & 0x3f], - tagSymbolSpace[(tag >> 0) & 0x3f], - ]; - - tagBuffer = chars.join(""); - - return tagBuffer; - } -} diff --git a/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts b/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts index ee9d378dea..4023566560 100644 --- a/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts +++ b/extensions/msal-node-extensions/test/broker/NativeBrokerPlugin.spec.ts @@ -51,10 +51,10 @@ import { ServerError, TimeUtils, Constants, + PlatformBrokerError, + ClientAuthError, } from "@azure/msal-common"; import { randomUUID } from "crypto"; -import { NativeAuthError } from "../../src/error/NativeAuthError"; -import { StringUtils } from "../../src/utils/StringUtils.js"; import { testMsalRuntimeAccount, testAccountInfo, @@ -86,24 +86,19 @@ function createMockAuthResult( if (process.platform === "win32") { describe("NativeBrokerPlugin", () => { - const enhancedErrorContext = msalRuntimeExampleError.errorContext - ? `${msalRuntimeExampleError.errorContext} (Error Code: ${ - msalRuntimeExampleError.errorCode - }, Tag: ${StringUtils.tagToString( - msalRuntimeExampleError.errorTag - )})` - : `(Error Code: ${ - msalRuntimeExampleError.errorCode - }, Tag: ${StringUtils.tagToString( - msalRuntimeExampleError.errorTag - )})`; - const testNativeAuthError = new NativeAuthError( + const testPlatformBrokerError = new PlatformBrokerError( ErrorStatus[msalRuntimeExampleError.errorStatus], - enhancedErrorContext, + msalRuntimeExampleError.errorContext, msalRuntimeExampleError.errorCode, msalRuntimeExampleError.errorTag ); + // Expected wrapped error for the default case (Unexpected status) + const testWrappedBrokerError = createClientAuthError( + ClientAuthErrorCodes.platformBrokerError + ); + testWrappedBrokerError.platformBrokerError = testPlatformBrokerError; + const generateCorrelationId = () => { return randomUUID(); }; @@ -190,8 +185,13 @@ if (process.platform === "win32") { testCorrelationId ) .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + expect(error).toBeInstanceOf(ClientAuthError); + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError ); done(); }); @@ -232,8 +232,13 @@ if (process.platform === "win32") { testCorrelationId ) .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + expect(error).toBeInstanceOf(ClientAuthError); + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError ); done(); }); @@ -288,8 +293,13 @@ if (process.platform === "win32") { nativeBrokerPlugin .getAllAccounts(TEST_CLIENT_ID, testCorrelationId) .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + expect(error).toBeInstanceOf(ClientAuthError); + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError ); done(); }); @@ -325,8 +335,13 @@ if (process.platform === "win32") { nativeBrokerPlugin .getAllAccounts(TEST_CLIENT_ID, testCorrelationId) .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + expect(error).toBeInstanceOf(ClientAuthError); + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError ); done(); }); @@ -569,8 +584,13 @@ if (process.platform === "win32") { nativeBrokerPlugin .acquireTokenSilent(request) .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + expect(error).toBeInstanceOf(ClientAuthError); + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError ); done(); }); @@ -597,8 +617,13 @@ if (process.platform === "win32") { nativeBrokerPlugin .acquireTokenSilent(request) .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + expect(error).toBeInstanceOf(ClientAuthError); + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError ); done(); }); @@ -647,9 +672,12 @@ if (process.platform === "win32") { }; nativeBrokerPlugin .acquireTokenSilent(request) - .catch((error) => { - expect(error).toStrictEqual( - testNativeAuthError + .catch((error: ClientAuthError) => { + expect(error.errorCode).toBe( + ClientAuthErrorCodes.platformBrokerError + ); + expect(error.platformBrokerError).toStrictEqual( + testPlatformBrokerError ); done(); }); @@ -1232,7 +1260,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.acquireTokenInteractive(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("Throws error if AcquireTokenInteractivelyAsync returns error", async () => { @@ -1302,7 +1330,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.acquireTokenInteractive(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("Throws error if SignInAsync returns error", async () => { @@ -1347,7 +1375,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.acquireTokenInteractive(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("Throws error if AcquireTokenSilentlyAsync returns error", async () => { @@ -1416,7 +1444,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.acquireTokenInteractive(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("Throws error if SignInSilentlyAsync returns error", async () => { @@ -1463,7 +1491,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.acquireTokenInteractive(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("Throws error if MsalRuntime API throws", async () => { @@ -1485,7 +1513,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.acquireTokenInteractive(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("sets the correct redirectUri when calling acquireTokenInteractive", async () => { @@ -1680,7 +1708,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.signOut(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); it("Throws error if SignOutSilentlyAsync API throws", async () => { @@ -1721,7 +1749,7 @@ if (process.platform === "win32") { }; await expect( nativeBrokerPlugin.signOut(request) - ).rejects.toThrowError(testNativeAuthError); + ).rejects.toThrow(testWrappedBrokerError); }); }); @@ -2256,6 +2284,69 @@ if (process.platform === "win32") { done(); }); }); + + it("Attaches platformBrokerError with runtime details to wrapped MSAL.js errors", (done) => { + const testCorrelationId = generateCorrelationId(); + + jest.spyOn( + msalNodeRuntime, + "SignInSilentlyAsync" + ).mockImplementation( + ( + authParams: AuthParameters, + correlationId: string, + callback: (result: AuthResult) => void + ) => { + const result: AuthResult = { + idToken: "", + accessToken: "", + authorizationHeader: "", + rawIdToken: "", + grantedScopes: "", + expiresOn: 0, + isPopAuthorization: false, + account: testMsalRuntimeAccount, + CheckError: () => { + const testError: MsalRuntimeError = { + errorCode: 0, + errorStatus: + ErrorStatus.InteractionRequired, + errorContext: "", + errorTag: 0, + }; + throw testError; + }, + telemetryData: "", + }; + expect(correlationId).toEqual(testCorrelationId); + callback(result); + + return asyncHandle; + } + ); + + const nativeBrokerPlugin = new NativeBrokerPlugin(); + const request: NativeRequest = { + clientId: TEST_CLIENT_ID, + scopes: [], + correlationId: testCorrelationId, + authority: "", + redirectUri: TEST_REDIRECTURI, + }; + + nativeBrokerPlugin + .acquireTokenSilent(request) + .catch((error) => { + expect(error).toBeInstanceOf( + InteractionRequiredAuthError + ); + expect(error.platformBrokerError).toBeDefined(); + expect(error.platformBrokerError).toBeInstanceOf( + PlatformBrokerError + ); + done(); + }); + }); }); }); } else if (process.platform === "darwin") { diff --git a/extensions/msal-node-extensions/test/utils/StringUtils.test.ts b/extensions/msal-node-extensions/test/utils/StringUtils.test.ts deleted file mode 100644 index f5d26d6add..0000000000 --- a/extensions/msal-node-extensions/test/utils/StringUtils.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */ - -import { StringUtils } from "../../src/utils/StringUtils.js"; - -describe("StringUtils", () => { - describe("tagToString tests", () => { - it("Returns 'UNTAG' for tag value 0", () => { - expect(StringUtils.tagToString(0)).toBe("UNTAG"); - }); - - it("Converts numeric tag to 5-character string", () => { - const tag = 0x01234567; - const result = StringUtils.tagToString(tag); - - expect(result).toHaveLength(5); - expect(typeof result).toBe("string"); - }); - - it("Produce same results for same input", () => { - const tag = 0x12345678; - const result1 = StringUtils.tagToString(tag); - const result2 = StringUtils.tagToString(tag); - - expect(result1).toBe(result2); - }); - }); -}); diff --git a/lib/msal-common/apiReview/msal-common.api.md b/lib/msal-common/apiReview/msal-common.api.md index bfc0c2f6f9..0ec87772bf 100644 --- a/lib/msal-common/apiReview/msal-common.api.md +++ b/lib/msal-common/apiReview/msal-common.api.md @@ -587,6 +587,7 @@ export class AuthError extends Error { correlationId: string; errorCode: string; errorMessage: string; + platformBrokerError?: PlatformBrokerError; // (undocumented) setCorrelationId(correlationId: string): void; subError: string; @@ -1502,7 +1503,8 @@ declare namespace ClientAuthErrorCodes { noNetworkConnectivity, userCanceled, methodNotImplemented, - nestedAppAuthBridgeDisabled + nestedAppAuthBridgeDisabled, + platformBrokerError } } export { ClientAuthErrorCodes } @@ -3554,6 +3556,19 @@ const pkceParamsMissing = "pkce_params_missing"; // // @public const PopTokenGenerateCnf = "popTokenGenerateCnf"; +// Warning: (ae-missing-release-tag) "PlatformBrokerError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export class PlatformBrokerError extends AuthError { + constructor(errorStatus: string, errorContext: string, errorCode: number, errorTag: number); + statusCode: number; + tag: string; +} + +// Warning: (ae-missing-release-tag) "platformBrokerError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +const platformBrokerError = "platform_broker_error"; // Warning: (ae-internal-missing-underscore) The name "PopTokenGenerator" should be prefixed with an underscore because the declaration is marked as @internal // diff --git a/lib/msal-common/src/error/AuthError.ts b/lib/msal-common/src/error/AuthError.ts index 9a7f00ccd4..33d134fcee 100644 --- a/lib/msal-common/src/error/AuthError.ts +++ b/lib/msal-common/src/error/AuthError.ts @@ -4,6 +4,7 @@ */ import * as AuthErrorCodes from "./AuthErrorCodes.js"; +import type { PlatformBrokerError } from "./PlatformBrokerError.js"; export { AuthErrorCodes }; export function getDefaultErrorMessage(code: string): string { @@ -34,6 +35,11 @@ export class AuthError extends Error { */ correlationId: string; + /** + * Default PlatformBrokerError from MsalNodeRuntime when broker is enabled + */ + platformBrokerError?: PlatformBrokerError; + constructor(errorCode?: string, errorMessage?: string, suberror?: string) { const message = errorMessage || diff --git a/lib/msal-common/src/error/ClientAuthErrorCodes.ts b/lib/msal-common/src/error/ClientAuthErrorCodes.ts index 628019117a..c2fcd10169 100644 --- a/lib/msal-common/src/error/ClientAuthErrorCodes.ts +++ b/lib/msal-common/src/error/ClientAuthErrorCodes.ts @@ -42,3 +42,4 @@ export const noNetworkConnectivity = "no_network_connectivity"; export const userCanceled = "user_canceled"; export const methodNotImplemented = "method_not_implemented"; export const nestedAppAuthBridgeDisabled = "nested_app_auth_bridge_disabled"; +export const platformBrokerError = "platform_broker_error"; diff --git a/lib/msal-common/src/error/PlatformBrokerError.ts b/lib/msal-common/src/error/PlatformBrokerError.ts new file mode 100644 index 0000000000..6085fd9498 --- /dev/null +++ b/lib/msal-common/src/error/PlatformBrokerError.ts @@ -0,0 +1,66 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +import { AuthError } from "./AuthError.js"; + +/** + * Converts a numeric tag to a string representation + * @param tag - The numeric tag to convert + * @returns The string representation of the tag + */ +function tagToString(tag: number): string { + if (tag === 0) { + return "UNTAG"; + } + + const tagSymbolSpace = + "abcdefghijklmnopqrstuvwxyz0123456789****************************"; + let tagBuffer = "*****"; + + const chars = [ + tagSymbolSpace[(tag >> 24) & 0x3f], + tagSymbolSpace[(tag >> 18) & 0x3f], + tagSymbolSpace[(tag >> 12) & 0x3f], + tagSymbolSpace[(tag >> 6) & 0x3f], + tagSymbolSpace[(tag >> 0) & 0x3f], + ]; + + tagBuffer = chars.join(""); + + return tagBuffer; +} + +/** + * Error class for MSAL Runtime errors that preserves detailed broker information + */ +export class PlatformBrokerError extends AuthError { + /** + * Numeric error code from MSAL Runtime + */ + public statusCode: number; + + /** + * Error tag from MSAL Runtime + */ + public tag: string; + + constructor( + errorStatus: string, + errorContext: string, + errorCode: number, + errorTag: number + ) { + const tagString = tagToString(errorTag); + const enhancedErrorContext = errorContext + ? `${errorContext} (Error Code: ${errorCode}, Tag: ${tagString})` + : `(Error Code: ${errorCode}, Tag: ${tagString})`; + + super(errorStatus, enhancedErrorContext); + this.name = "PlatformBrokerError"; + this.statusCode = errorCode; + this.tag = tagString; + Object.setPrototypeOf(this, PlatformBrokerError.prototype); + } +} diff --git a/lib/msal-common/src/exports-common.ts b/lib/msal-common/src/exports-common.ts index 6b0cdca41c..ae44c80f3a 100644 --- a/lib/msal-common/src/exports-common.ts +++ b/lib/msal-common/src/exports-common.ts @@ -140,6 +140,7 @@ export { AuthErrorCodes, createAuthError, } from "./error/AuthError.js"; +export { PlatformBrokerError } from "./error/PlatformBrokerError.js"; export { ServerError } from "./error/ServerError.js"; export { NetworkError, createNetworkError } from "./error/NetworkError.js"; export { From df22efa3cf0b13f63a1939a86a14df2199a53cc2 Mon Sep 17 00:00:00 2001 From: Ugonna Akali Date: Wed, 19 Nov 2025 10:55:54 -0800 Subject: [PATCH 07/12] additional changes --- ...e-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json | 2 +- ...-extensions-bce3798f-5840-4955-a647-70f9009359fc.json | 2 +- docs/errors.md | 2 +- .../src/broker/NativeBrokerPlugin.ts | 2 +- lib/msal-common/apiReview/msal-common.api.md | 9 +++++---- lib/msal-common/src/error/PlatformBrokerError.ts | 3 ++- lib/msal-node/src/client/PublicClientApplication.ts | 2 +- lib/msal-node/src/request/InteractiveRequest.ts | 5 +---- 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json b/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json index d6fc58b438..799479f98d 100644 --- a/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json +++ b/change/@azure-msal-node-118ac835-7803-4e30-81cd-91c4afe6bf9d.json @@ -1,6 +1,6 @@ { "type": "patch", - "comment": "enable passing of redirect uri", + "comment": "Enable passing of redirect uri to broker plugin #8153", "packageName": "@azure/msal-node", "email": "akaliugonna@microsoft.com", "dependentChangeType": "patch" diff --git a/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json b/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json index bf5495cbdb..fd069eaef9 100644 --- a/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json +++ b/change/@azure-msal-node-extensions-bce3798f-5840-4955-a647-70f9009359fc.json @@ -1,6 +1,6 @@ { "type": "patch", - "comment": "enable passing of redirect uri", + "comment": "Enable passing of redirect uri to broker plugin #8153", "packageName": "@azure/msal-node-extensions", "email": "akaliugonna@microsoft.com", "dependentChangeType": "patch" diff --git a/docs/errors.md b/docs/errors.md index c4c1bb5c7f..9e1a6f3566 100644 --- a/docs/errors.md +++ b/docs/errors.md @@ -173,7 +173,7 @@ This error occurs when MSAL.js surpasses the allotted storage limit when attempt - The nested app auth bridge is disabled. ### `platform_broker_error` -- An error occurred in the native broker. See the platformBrokerError property for details. +- An error occurred in the native broker. When this error is thrown, check the `platformBrokerError` property on the error object for detailed information. ## Client configuration errors diff --git a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts index af97819a2b..82dbddc66a 100644 --- a/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts +++ b/extensions/msal-node-extensions/src/broker/NativeBrokerPlugin.ts @@ -684,7 +684,7 @@ export class NativeBrokerPlugin implements INativeBrokerPlugin { case ErrorStatus.ServerTemporarilyUnavailable: wrappedError = new ServerError( ErrorCodes.SERVER_UNAVAILABLE, - errorContext + msalNodeRuntimeError.message ); break; case ErrorStatus.UserCanceled: diff --git a/lib/msal-common/apiReview/msal-common.api.md b/lib/msal-common/apiReview/msal-common.api.md index 0ec87772bf..9a710f8ddb 100644 --- a/lib/msal-common/apiReview/msal-common.api.md +++ b/lib/msal-common/apiReview/msal-common.api.md @@ -3552,10 +3552,6 @@ export type PkceCodes = { // @public (undocumented) const pkceParamsMissing = "pkce_params_missing"; -// Warning: (ae-missing-release-tag) "PopTokenGenerateCnf" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public -const PopTokenGenerateCnf = "popTokenGenerateCnf"; // Warning: (ae-missing-release-tag) "PlatformBrokerError" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -3570,6 +3566,11 @@ export class PlatformBrokerError extends AuthError { // @public (undocumented) const platformBrokerError = "platform_broker_error"; +// Warning: (ae-missing-release-tag) "PopTokenGenerateCnf" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +const PopTokenGenerateCnf = "popTokenGenerateCnf"; + // Warning: (ae-internal-missing-underscore) The name "PopTokenGenerator" should be prefixed with an underscore because the declaration is marked as @internal // // @internal (undocumented) diff --git a/lib/msal-common/src/error/PlatformBrokerError.ts b/lib/msal-common/src/error/PlatformBrokerError.ts index 6085fd9498..e9da293e63 100644 --- a/lib/msal-common/src/error/PlatformBrokerError.ts +++ b/lib/msal-common/src/error/PlatformBrokerError.ts @@ -6,7 +6,8 @@ import { AuthError } from "./AuthError.js"; /** - * Converts a numeric tag to a string representation + * Converts a numeric tag from MSAL Runtime to a 5-character string representation. + * Tags are encoded as 30-bit values (6 bits per character) using a custom symbol space. * @param tag - The numeric tag to convert * @returns The string representation of the tag */ diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index 352d28f55e..b55699b244 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -178,7 +178,7 @@ export class PublicClientApplication } if (request.redirectUri) { - // If its not a broker fallback scenario, we throw a error + // If it's not a broker fallback scenario, we throw an error if (!this.config.broker.nativeBrokerPlugin) { throw NodeAuthError.createRedirectUriNotSupportedError(); } diff --git a/lib/msal-node/src/request/InteractiveRequest.ts b/lib/msal-node/src/request/InteractiveRequest.ts index 3a2e67ada1..7ef27b0de8 100644 --- a/lib/msal-node/src/request/InteractiveRequest.ts +++ b/lib/msal-node/src/request/InteractiveRequest.ts @@ -18,10 +18,7 @@ import { ILoopbackClient } from "../network/ILoopbackClient.js"; * @public */ export type InteractiveRequest = Partial< - Omit< - CommonAuthorizationUrlRequest, - "scopes" | "storeInCache" - > + Omit > & { openBrowser: (url: string) => Promise; scopes?: Array; From 42a968cf5ea600ca363cd53c805c3498e75cf9df Mon Sep 17 00:00:00 2001 From: Ugonna Akali Date: Fri, 21 Nov 2025 08:52:53 -0800 Subject: [PATCH 08/12] update package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 32cd019083..e61a1590d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3700,9 +3700,9 @@ "link": true }, "node_modules/@azure/msal-node-runtime": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.20.0.tgz", - "integrity": "sha512-lmCO41fjY2BmPnRMTDEwHmTlYVw5AV+7TiNFHpwVUbt/qZtKv/2tQAlCLISXIeY/xA6COtO++MUmDfB6XdR4LA==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node-runtime/-/msal-node-runtime-0.20.1.tgz", + "integrity": "sha512-WVbMedbJHjt9M+qeZMH/6U1UmjXsKaMB6fN8OZUtGY7UVNYofrowZNx4nVvWN/ajPKBQCEW4Rr/MwcRuA8HGcQ==", "hasInstallScript": true, "license": "MIT" }, From 144839410aa16313fbe47ebec215e0fe9a62ec29 Mon Sep 17 00:00:00 2001 From: Ugonna Akali Date: Fri, 21 Nov 2025 12:46:56 -0800 Subject: [PATCH 09/12] grammer --- lib/msal-node/src/client/PublicClientApplication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msal-node/src/client/PublicClientApplication.ts b/lib/msal-node/src/client/PublicClientApplication.ts index b55699b244..79e54513f8 100644 --- a/lib/msal-node/src/client/PublicClientApplication.ts +++ b/lib/msal-node/src/client/PublicClientApplication.ts @@ -281,7 +281,7 @@ export class PublicClientApplication } if (request.redirectUri) { - // If its not a broker fallback scenario, we throw a error + // If it's not a broker fallback scenario, we throw an error if (!this.config.broker.nativeBrokerPlugin) { throw NodeAuthError.createRedirectUriNotSupportedError(); } From 7de1a9c9ed4fbde19ca82e80bd3e1bc9fd8a6d07 Mon Sep 17 00:00:00 2001 From: Ugonna Akali Date: Fri, 21 Nov 2025 13:08:41 -0800 Subject: [PATCH 10/12] fix test failure --- lib/msal-node/test/client/PublicClientApplication.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msal-node/test/client/PublicClientApplication.spec.ts b/lib/msal-node/test/client/PublicClientApplication.spec.ts index 9165c6f995..446cdc61df 100644 --- a/lib/msal-node/test/client/PublicClientApplication.spec.ts +++ b/lib/msal-node/test/client/PublicClientApplication.spec.ts @@ -651,14 +651,14 @@ describe("PublicClientApplication", () => { const silentFlowClient = getMsalCommonAutoMock().SilentFlowClient; jest.spyOn(msalCommon, "SilentFlowClient").mockImplementation( - (config) => new silentFlowClient(config) + (config) => new silentFlowClient(config, new StubPerformanceClient()) ); jest.spyOn( silentFlowClient.prototype, "acquireCachedToken" ).mockResolvedValue([ mockAuthenticationResult, - CacheOutcome.NOT_APPLICABLE, + CommonConstants.CacheOutcome.NOT_APPLICABLE, ]); const request: SilentFlowRequest = { From dd93a0734a95dbe60a42f08455d4c0307c2816a9 Mon Sep 17 00:00:00 2001 From: Ugonna Akali Date: Fri, 21 Nov 2025 13:09:11 -0800 Subject: [PATCH 11/12] fic test failure --- lib/msal-node/test/client/PublicClientApplication.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/msal-node/test/client/PublicClientApplication.spec.ts b/lib/msal-node/test/client/PublicClientApplication.spec.ts index 446cdc61df..6d0d0133bf 100644 --- a/lib/msal-node/test/client/PublicClientApplication.spec.ts +++ b/lib/msal-node/test/client/PublicClientApplication.spec.ts @@ -651,7 +651,8 @@ describe("PublicClientApplication", () => { const silentFlowClient = getMsalCommonAutoMock().SilentFlowClient; jest.spyOn(msalCommon, "SilentFlowClient").mockImplementation( - (config) => new silentFlowClient(config, new StubPerformanceClient()) + (config) => + new silentFlowClient(config, new StubPerformanceClient()) ); jest.spyOn( silentFlowClient.prototype, From d4cc454463034e92438e7af624c8e178bc6a0641 Mon Sep 17 00:00:00 2001 From: Ugonna Akali Date: Fri, 21 Nov 2025 15:42:18 -0800 Subject: [PATCH 12/12] Trigger CI re-run