Skip to content

Commit 1fff290

Browse files
lalimashardaCopilotCopilottnorling
authored
Add allowPlatformBrokerWithDOM experimental config flag (#8589)
Add experimental config flag 'allowPlatformBrokerWithDOM' under BrowserExperimentalOptions to enable platform broker support through DOM APIs in Edge. When both allowPlatformBroker and allowPlatformBrokerWithDOM are set, MSAL first checks for DOM API availability before falling back to PlatformAuthExtensionHandler. - Add allowPlatformBrokerWithDOM to BrowserExperimentalOptions (default: false) - Replace session storage-based isDomEnabledForPlatformAuth with explicit config parameter - Add invalidPlatformBrokerConfiguration error code for invalid config combinations - Add config validation in isPlatformAuthAllowed - Pass config flag through StandardController to getPlatformAuthProvider --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lalimasharda <26092202+lalimasharda@users.noreply.github.com> Co-authored-by: Thomas Norling <thomas.norling@microsoft.com>
1 parent 99e0895 commit 1fff290

13 files changed

Lines changed: 160 additions & 151 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Add allowPlatformBrokerWithDOM experimental config flag for DOM-based platform brokering [#8589](https://github.com/AzureAD/microsoft-authentication-library-for-js/pull/8589)",
4+
"packageName": "@azure/msal-browser",
5+
"email": "lalimasharda@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Add invalidPlatformBrokerConfiguration error code for DOM-based platform brokering [#8589](https://github.com/AzureAD/microsoft-authentication-library-for-js/pull/8589)",
4+
"packageName": "@azure/msal-common",
5+
"email": "lalimasharda@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

docs/errors.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ This error occurs when MSAL.js surpasses the allotted storage limit when attempt
261261

262262
- Cannot set allowPlatformBroker parameter to true when not in AAD protocol mode.
263263

264+
### `invalid_platform_broker_configuration`
265+
266+
- Invalid platform broker configuration. `allowPlatformBrokerWithDOM` requires `allowPlatformBroker` to also be set to `true`.
267+
264268
### `authority_mismatch`
265269

266270
- Authority mismatch error. Authority provided in login request or PublicClientApplication config does not match the environment of the provided account. Please use a matching account or make an interactive request to login to this authority.

lib/msal-browser/apiReview/msal-browser.api.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ export { BrowserConfigurationAuthErrorCodes }
339339
// @internal (undocumented)
340340
export type BrowserExperimentalOptions = {
341341
iframeTimeoutTelemetry?: boolean;
342+
allowPlatformBrokerWithDOM?: boolean;
342343
};
343344

344345
// Warning: (ae-missing-release-tag) "BrowserPerformanceClient" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -911,13 +912,10 @@ function isInIframe(): boolean;
911912
// @public
912913
function isInPopup(): boolean;
913914

914-
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
915-
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
916-
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
917915
// Warning: (ae-missing-release-tag) "isPlatformBrokerAvailable" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
918916
//
919917
// @public
920-
export function isPlatformBrokerAvailable(loggerOptions?: LoggerOptions, perfClient?: IPerformanceClient, correlationId?: string): Promise<boolean>;
918+
export function isPlatformBrokerAvailable(domConfig: boolean, loggerOptions?: LoggerOptions, perfClient?: IPerformanceClient, correlationId?: string): Promise<boolean>;
921919

922920
// Warning: (ae-missing-release-tag) "IWindowStorage" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
923921
//
@@ -1544,8 +1542,8 @@ export type WrapperSKU = (typeof WrapperSKU)[keyof typeof WrapperSKU];
15441542
// src/cache/LocalStorage.ts:366:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
15451543
// src/cache/LocalStorage.ts:429:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
15461544
// src/cache/LocalStorage.ts:460:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1547-
// src/config/Configuration.ts:213:5 - (ae-incompatible-release-tags) The symbol "experimental" is marked as @public, but its signature references "BrowserExperimentalOptions" which is marked as @internal
1548-
// src/config/Configuration.ts:222:5 - (ae-forgotten-export) The symbol "InternalAuthOptions" needs to be exported by the entry point index.d.ts
1545+
// src/config/Configuration.ts:217:5 - (ae-incompatible-release-tags) The symbol "experimental" is marked as @public, but its signature references "BrowserExperimentalOptions" which is marked as @internal
1546+
// src/config/Configuration.ts:226:5 - (ae-forgotten-export) The symbol "InternalAuthOptions" needs to be exported by the entry point index.d.ts
15491547
// src/event/EventHandler.ts:116:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
15501548
// src/event/EventHandler.ts:143:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
15511549
// src/index.ts:8:12 - (tsdoc-characters-after-block-tag) The token "@azure" looks like a TSDoc tag but contains an invalid character "/"; if it is not a tag, use a backslash to escape the "@"

lib/msal-browser/docs/device-bound-tokens.md

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# Acquiring Device Bound Tokens using Web Account Manager (WAM) on Windows
1+
# Acquiring Device Bound Tokens using platform brokers
22

3-
MSAL.js supports acquiring tokens from the Web Account Manager (WAM) on Windows. These tokens are bound to the device they were acquired on and are not cached in the browser's localStorage or sessionStorage.
3+
MSAL.js supports acquiring tokens from the platform broker, say Web Account Manager (WAM) on Windows and Mac Broker on Mac. These tokens are bound to the device they were acquired on and are not cached in the browser's localStorage or sessionStorage.
44

55
## Supported Environment
66

77
This feature is currently only supported in the following environment:
88

9-
- A machine running a Windows build that supports the feature (more to come on this)
9+
- A machine running a Windows build that supports the feature (more to come on this) or a Company Portal managed Mac with a specific Mac OS version (more to come on this).
1010
- Chrome and Edge browsers or Teams
1111
- [Windows Accounts extension](https://chrome.google.com/webstore/detail/windows-accounts/ppnbnpeolgkicgegkbkbjmhlideopiji) (version 1.0.5 or higher) is installed if using Chrome or Edge
1212
- App must be hosted on `https`
@@ -45,10 +45,37 @@ pca.acquireTokenSilent();
4545

4646
No other changes are needed to support this new feature. Any user accessing your app from a supported environment will now be able to acquire device bound tokens. Users in non-supported environments will continue to acquire tokens through the traditional web-based flows.
4747

48-
## Differences when using WAM to acquire tokens
48+
## Differences when using Platform Broker to acquire tokens
4949

50-
There are a few things that may behave a little differently when acquiring tokens through WAM.
50+
There are a few things that may behave a little differently when acquiring tokens through the platform broker.
5151

52-
- All cache related configuration applies only to MSAL's local cache. The native broker controls its own, more secure, cache which is used instead of browser storage and it does not support configuration of its cache behavior. This means you may receive a cached token regardless of the value of request parameters such as: `forceRefresh`, `cacheLookupPolicy` or `storeInCache`. In addition, tokens received from the native broker are _not_ stored in local or session storage regardless of what you have configured on PublicClientApplication.
53-
- If WAM needs to prompt the user for interaction a system prompt will be opened. This prompt looks a bit different from the browser popup windows you may be used to.
54-
- Switching your account in the WAM prompt is not supported and MSAL.js will throw an error (Error Code: user_switch) if this happens. It is your app's responsibility to catch this error and handle it in a way that makes sense for your scenarios (e.g. Show an error page, retry with the new account, retry with the original account, etc.)
52+
- All cache related configuration applies only to MSAL's local cache. The platform broker controls its own, more secure, cache which is used instead of browser storage and it does not support configuration of its cache behavior. This means you may receive a cached token regardless of the value of request parameters such as: `forceRefresh`, `cacheLookupPolicy` or `storeInCache`. In addition, tokens received from the platform broker are _not_ stored in local or session storage regardless of what you have configured on PublicClientApplication.
53+
- If the platform broker needs to prompt the user for interaction a system prompt will be opened. This prompt looks a bit different from the browser popup windows you may be used to.
54+
- Switching your account in the platform broker prompt is not supported and MSAL.js will throw an error (Error Code: user_switch) if this happens. It is your app's responsibility to catch this error and handle it in a way that makes sense for your scenarios (e.g. Show an error page, retry with the new account, retry with the original account, etc.)
55+
56+
## Acquiring Device Bound Tokens using DOM API
57+
58+
MSAL.js also supports acquiring tokens from the platform broker using DOM APIs in Edge. Instead of using a browser extension to communicate with the platform broker, MSAL.js can directly call a DOM API in the Edge browser, which in turn invokes the platform broker to acquire tokens.
59+
60+
- This feature is currently only supported in the Edge browser and all other OS requirements mentioned above still apply. (more details to come).
61+
- This feature is currently only in private-preview and requires special enablement.
62+
63+
To enable this feature, set the `allowPlatformBrokerWithDOM` flag to true in the `experimental` section of your configuration object like so:
64+
65+
```javascript
66+
const msalConfig = {
67+
auth: {
68+
clientId: "insert-clientId",
69+
},
70+
system: {
71+
allowPlatformBroker: true,
72+
},
73+
experimental: {
74+
allowPlatformBrokerWithDOM: true,
75+
},
76+
};
77+
```
78+
79+
Note: The `allowPlatformBroker` flag must also be set to true in order to use this feature. There will be a configuration error - `invalid_platform_broker_configuration` if `allowPlatformBrokerWithDOM` is set to true while `allowPlatformBroker` is false.
80+
81+
Eventually, in a future major version, this flag will be merged with `allowPlatformBroker` and MSAL.js will make the decision to use either the browser extension or DOM APIs based on the environment automatically. The behavior and availability of `experimental` flags is subject to change at any time, without following semver rules.

lib/msal-browser/src/broker/nativeBroker/PlatformAuthProvider.ts

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
Logger,
1010
Constants,
1111
StubPerformanceClient,
12+
createClientConfigurationError,
13+
ClientConfigurationErrorCodes,
1214
} from "@azure/msal-common/browser";
1315
import { name, version } from "../../packageMetadata.js";
1416
import {
@@ -18,50 +20,57 @@ import {
1820
import { PlatformAuthExtensionHandler } from "./PlatformAuthExtensionHandler.js";
1921
import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js";
2022
import { PlatformAuthDOMHandler } from "./PlatformAuthDOMHandler.js";
21-
import { BrowserCacheLocation } from "../../utils/BrowserConstants.js";
22-
import { PLATFORM_AUTH_DOM_SUPPORT } from "../../cache/CacheKeys.js";
23+
import { createNewGuid } from "../../crypto/BrowserCrypto.js";
2324

2425
/**
2526
* Checks if the platform broker is available in the current environment.
26-
* @param loggerOptions
27-
* @param perfClient
28-
* @param correlationId
29-
* @returns
27+
* @param domConfig - Whether to enable platform broker DOM API support (required)
28+
* @param loggerOptions - Optional logger options
29+
* @param perfClient - Optional performance client
30+
* @param correlationId - Optional correlation ID
31+
* @returns Promise<boolean> indicating if platform broker is available
3032
*/
3133
export async function isPlatformBrokerAvailable(
34+
domConfig: boolean,
3235
loggerOptions?: LoggerOptions,
3336
perfClient?: IPerformanceClient,
3437
correlationId?: string
3538
): Promise<boolean> {
3639
const logger = new Logger(loggerOptions || {}, name, version);
37-
const cid = correlationId || "";
38-
39-
logger.trace("isPlatformBrokerAvailable called", cid);
4040

4141
const performanceClient = perfClient || new StubPerformanceClient();
4242

4343
if (typeof window === "undefined") {
44-
logger.trace("Non-browser environment detected, returning false", cid);
44+
logger.trace(
45+
"Non-browser environment detected, returning false",
46+
correlationId || createNewGuid()
47+
);
4548
return false;
4649
}
4750

48-
return !!(await getPlatformAuthProvider(logger, performanceClient, cid));
51+
return !!(await getPlatformAuthProvider(
52+
logger,
53+
performanceClient,
54+
correlationId || createNewGuid(),
55+
undefined,
56+
domConfig
57+
));
4958
}
5059

5160
export async function getPlatformAuthProvider(
5261
logger: Logger,
5362
performanceClient: IPerformanceClient,
5463
correlationId: string,
55-
nativeBrokerHandshakeTimeout?: number
64+
nativeBrokerHandshakeTimeout?: number,
65+
enablePlatformBrokerDOMSupport?: boolean
5666
): Promise<IPlatformAuthHandler | undefined> {
5767
logger.trace("getPlatformAuthProvider called", correlationId);
5868

59-
const enablePlatformBrokerDOMSupport = isDomEnabledForPlatformAuth();
60-
6169
logger.trace(
6270
`Has client allowed platform auth via DOM API: '${enablePlatformBrokerDOMSupport}'`,
6371
correlationId
6472
);
73+
6574
let platformAuthProvider: IPlatformAuthHandler | undefined;
6675
try {
6776
if (enablePlatformBrokerDOMSupport) {
@@ -96,22 +105,6 @@ export async function getPlatformAuthProvider(
96105
return platformAuthProvider;
97106
}
98107

99-
/**
100-
* Returns true if the DOM API support for platform auth is enabled in session storage
101-
* @returns boolean
102-
* @deprecated
103-
*/
104-
export function isDomEnabledForPlatformAuth(): boolean {
105-
let sessionStorage: Storage | undefined;
106-
try {
107-
sessionStorage = window[BrowserCacheLocation.SessionStorage];
108-
// Mute errors if it's a non-browser environment or cookies are blocked.
109-
return sessionStorage?.getItem(PLATFORM_AUTH_DOM_SUPPORT) === "true";
110-
} catch (e) {
111-
return false;
112-
}
113-
}
114-
115108
/**
116109
* Returns boolean indicating whether or not the request should attempt to use platform broker
117110
* @param logger
@@ -128,6 +121,17 @@ export function isPlatformAuthAllowed(
128121
authenticationScheme?: Constants.AuthenticationScheme
129122
): boolean {
130123
logger.trace("isPlatformAuthAllowed called", correlationId);
124+
125+
// throw an error if allowPlatformBroker is not enabled and allowPlatformBrokerWithDOM is enabled
126+
if (
127+
!config.system.allowPlatformBroker &&
128+
config.experimental.allowPlatformBrokerWithDOM
129+
) {
130+
throw createClientConfigurationError(
131+
ClientConfigurationErrorCodes.invalidPlatformBrokerConfiguration
132+
);
133+
}
134+
131135
if (!config.system.allowPlatformBroker) {
132136
logger.trace(
133137
"isPlatformAuthAllowed: allowPlatformBroker is not enabled, returning false",

lib/msal-browser/src/config/Configuration.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ export type BrowserExperimentalOptions = {
175175
* Enables iframe timeout telemetry experiment for silent iframe bridge monitoring.
176176
*/
177177
iframeTimeoutTelemetry?: boolean;
178+
/**
179+
* Flag to enable native broker support through DOM APIs in Edge
180+
*/
181+
allowPlatformBrokerWithDOM?: boolean;
178182
};
179183

180184
/**
@@ -329,6 +333,7 @@ export function buildConfiguration(
329333

330334
const DEFAULT_EXPERIMENTAL_OPTIONS: Required<BrowserExperimentalOptions> = {
331335
iframeTimeoutTelemetry: false,
336+
allowPlatformBrokerWithDOM: false,
332337
};
333338

334339
// Throw an error if user has set OIDCOptions without being in OIDC protocol mode

lib/msal-browser/src/controllers/StandardController.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ export class StandardController implements IController {
369369
this.logger,
370370
this.performanceClient,
371371
correlationId,
372-
this.config.system.nativeBrokerHandshakeTimeout
372+
this.config.system.nativeBrokerHandshakeTimeout,
373+
this.config.experimental.allowPlatformBrokerWithDOM
373374
);
374375
} catch (e) {
375376
this.logger.verbose(e as string, correlationId);

lib/msal-browser/test/app/PublicClientApplication.spec.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -499,13 +499,6 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
499499
},
500500
};
501501

502-
jest.spyOn(
503-
PlatformAuthProvider,
504-
"isDomEnabledForPlatformAuth"
505-
).mockImplementation(() => {
506-
return false;
507-
});
508-
509502
const getPlatformAuthProviderSpy = jest.spyOn(
510503
PlatformAuthProvider,
511504
"getPlatformAuthProvider"
@@ -558,7 +551,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
558551
expect(pca.platformAuthProvider).toBeUndefined();
559552
});
560553

561-
it("creates platform auth dom handler if allowPlatformBroker is true and dom APIs are present", async () => {
554+
it("creates platform auth dom handler if allowPlatformBrokerWithDOM is true and dom APIs are present", async () => {
562555
const getPlatformAuthProviderSpy = jest.spyOn(
563556
PlatformAuthProvider,
564557
"getPlatformAuthProvider"
@@ -571,13 +564,12 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
571564
system: {
572565
allowPlatformBroker: true,
573566
},
567+
experimental: {
568+
allowPlatformBrokerWithDOM: true,
569+
},
574570
};
575571

576572
pca = new PublicClientApplication(config);
577-
window.sessionStorage.setItem(
578-
"msal.browser.platform.auth.dom",
579-
"true"
580-
);
581573

582574
const createDOMProviderSpy = stubDOMProvider(config);
583575
await pca.initialize();

0 commit comments

Comments
 (0)