Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update current account and active account behavior in NAA apps #7390

Draft
wants to merge 4 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Update current account and active account behavior in NAA apps",
"packageName": "@azure/msal-browser",
"email": "[email protected]",
"dependentChangeType": "patch"
}
5 changes: 4 additions & 1 deletion lib/msal-browser/docs/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ As of `@azure/[email protected]`, all login hint values can be used to search f
- `username` account property
- `upn` ID token claim


> Note: All attributes above can be passed into the account filter as the `loginHint` property. The account filter will also accept the `username` attribute as `username`, and will yield a more performant search.

#### Using `login_hint` claim
Expand Down Expand Up @@ -158,6 +157,10 @@ function getAccessToken() {

Note: As of version 2.16.0 the active account is stored in the cache location configured on your `PublicClientApplication` instance. If you are using a previous version the active account is stored in-memory and thus must be reset on every page load.

### Nested App Authentication

For NAA applications, we consider `setActiveAccount()` and `getActiveAccount()` as NO-OP APIs. Though we allow users to set and get active accounts, they are actively ignored since the NAA application is always expected to have _one_ account and the account is supplied by the host application with `accountContext`. In the future when multiple accounts are supported across the hubs, we expect this to change.

## Notes

- The current msal-browser default [sample](../../../samples/msal-browser-samples/VanillaJSTestApp2.0) has a working single account scenario.
Expand Down
1 change: 1 addition & 0 deletions lib/msal-browser/docs/initialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Please note the below guidance before opting in for Nested app authentication:
- `supportsNestedAppAuth` in MSAL Browser configuration will be deprecated in the next major version. Please use `createNestablePublicClientApplication` instead.
- `createNestablePublicClientApplication` will fall back to `createStandardPublicClientApplication` if nested app bridge is unavailable or the Hub is not configured to support nested app authentication.
- If an application does not want to be Nested App, it should use `createStandardPublicClientApplication` instead.
- Certain account lookup APIs are not supported in NAA apps, please refer to [active accounts](./accounts.md#active-account-apis).

## Initializing the PublicClientApplication object

Expand Down
40 changes: 24 additions & 16 deletions lib/msal-browser/src/controllers/NestedAppAuthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
} from "../cache/BrowserCacheManager.js";
import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
import * as AccountManager from "../cache/AccountManager.js";
import { AccountContext } from "../naa/BridgeAccountContext.js";

export class NestedAppAuthController implements IController {
// OperatingContext
Expand Down Expand Up @@ -82,6 +83,9 @@ export class NestedAppAuthController implements IController {
// NestedAppAuthAdapter
protected readonly nestedAppAuthAdapter: NestedAppAuthAdapter;

// currentAccount for NAA apps
protected currentAccountContext: AccountContext | null;

constructor(operatingContext: NestedAppOperatingContext) {
this.operatingContext = operatingContext;
const proxy = this.operatingContext.getBridgeProxy();
Expand Down Expand Up @@ -130,15 +134,7 @@ export class NestedAppAuthController implements IController {

// Set the active account if available
const accountContext = this.bridgeProxy.getAccountContext();
if (accountContext) {
const cachedAccount = AccountManager.getAccount(
accountContext,
this.logger,
this.browserStorage
);

AccountManager.setActiveAccount(cachedAccount, this.browserStorage);
}
this.currentAccountContext = accountContext ? accountContext : null;
}

/**
Expand Down Expand Up @@ -224,7 +220,13 @@ export class NestedAppAuthController implements IController {
// cache the tokens in the response
await this.hydrateCache(result, request);

this.browserStorage.setActiveAccount(result.account);
// cache the account context in memory after successful token fetch
this.currentAccountContext = {
homeAccountId: result.account.homeAccountId,
environment: result.account.environment,
tenantId: result.account.tenantId,
};

this.eventHandler.emitEvent(
EventType.ACQUIRE_TOKEN_SUCCESS,
InteractionType.Popup,
Expand Down Expand Up @@ -318,7 +320,13 @@ export class NestedAppAuthController implements IController {
// cache the tokens in the response
await this.hydrateCache(result, request);

this.browserStorage.setActiveAccount(result.account);
// cache the account context in memory after successful token fetch
this.currentAccountContext = {
homeAccountId: result.account.homeAccountId,
environment: result.account.environment,
tenantId: result.account.tenantId,
};

this.eventHandler.emitEvent(
EventType.ACQUIRE_TOKEN_SUCCESS,
InteractionType.Silent,
Expand Down Expand Up @@ -428,16 +436,16 @@ export class NestedAppAuthController implements IController {
private async acquireTokenFromCacheInternal(
request: SilentRequest
): Promise<AuthenticationResult | null> {
const accountContext = this.bridgeProxy.getAccountContext();
let currentAccount = null;
// always prioritize the account context from the bridge
const accountContext =
this.bridgeProxy.getAccountContext() || this.currentAccountContext;
let currentAccount: AccountInfo | null = null;
if (accountContext) {
const hubAccount = AccountManager.getAccount(
currentAccount = AccountManager.getAccount(
accountContext,
this.logger,
this.browserStorage
);
// always prioritize for hub account context, the reqirement of `request.account` will be removed soon
currentAccount = hubAccount || request.account;
}

// fall back to brokering if no cached account is found
Expand Down
Loading