Skip to content

Remove getAccountBy APIs at controller level #7807

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

Open
wants to merge 6 commits into
base: msal-v5
Choose a base branch
from
Open
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": "major",
"comment": "Remove getAccountBy APIs at controller level #7807",
"packageName": "@azure/msal-browser",
"email": "[email protected]",
"dependentChangeType": "patch"
}
2 changes: 1 addition & 1 deletion lib/msal-angular/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Please see our [MsalGuard doc](https://github.com/AzureAD/microsoft-authenticati

### How do I get accounts?

The `@azure/msal-browser` instance used by `@azure/msal-angular` exposes multiple methods for getting account information. We recommend using `getAllAccounts()` to get all accounts, and `getAccountByHomeId()` and `getAccountByLocalId()` to get specific accounts. Note that while `getAccountByUsername()` is available, it should be a secondary choice, as it may be less reliable and is for convenience only. See the [`@azure/msal-browser` docs](https://azuread.github.io/microsoft-authentication-library-for-js/ref/classes/_azure_msal_browser.publicclientapplication.html) for more details on account methods.
The `@azure/msal-browser` instance used by `@azure/msal-angular` exposes multiple methods for getting account information. We recommend using `getAllAccounts()` to get all accounts, and `getAccount()` to get specific, filtered accounts. See the [`@azure/msal-browser` docs](https://azuread.github.io/microsoft-authentication-library-for-js/ref/classes/_azure_msal_browser.publicclientapplication.html) for more details on account methods.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be you can add an example for adding filter based on username or accountId, the most used filters.


We recommend subscribing to the `inProgress$` observable of `MsalBroadcastService` and filtering for `InteractionStatus.None` before retrieving account information. This ensures that all interactions have completed before getting account information. See [our sample](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/samples/msal-angular-samples/angular-modules-sample/src/app/app.component.ts#L45) for an example of this use.

Expand Down
6 changes: 3 additions & 3 deletions lib/msal-browser/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

1. [How do I specify which B2C policy/user flow I would like to use?](#how-do-i-specify-which-b2c-policyuser-flow-i-would-like-to-use)
1. [How do I handle the password-reset user-flow?](#how-do-i-handle-the-password-reset-user-flow)
1. [Why is getAccountByUsername returning null, even though I'm signed in?](#why-is-getaccountbyusername-returning-null-even-though-im-signed-in)
1. [Why is getAccount returning null when filtering by username even though I'm signed in?](#why-is-getaccount-returning-null-when-filtering-by-username-even-though-im-signed-in)
1. [I logged out of my application. Why am I not asked for credentials when I try to log back in?](#i-logged-out-of-my-application-why-am-i-not-asked-for-credentials-when-i-try-to-log-back-in)
1. [Why am I not signed in when returning from an invite link?](#why-am-i-not-signed-in-when-returning-from-an-invite-link)
1. [Why is there no access token returned from acquireTokenSilent?](#why-is-there-no-access-token-returned-from-acquiretokensilent)
Expand Down Expand Up @@ -428,9 +428,9 @@ pca.loginPopup()

For a full implementation, see the sample: [MSAL.js v2 B2C sample](https://github.com/Azure-Samples/ms-identity-javascript-tutorial/tree/main/1-Authentication/2-sign-in-b2c)

## Why is `getAccountByUsername()` returning null, even though I'm signed in?
## Why is getAccount returning null when filtering by username, even though I'm signed in?

In order to use `getAccountByUsername()` in B2C scenarios you must enable your `idTokens` to return the `emails` claim in your B2C tenant. MSAL will fill the `username` field on the `AccountInfo` object with the first element of the array returned on the `emails` claim. In most cases this array will only have one element, however, if you notice that your idTokens are returning more than one email on this claim, ensure you are calling `getAccountByUsername` with the first email.
In order to use `getAccount({ username })` in B2C scenarios you must enable your `idTokens` to return the `emails` claim in your B2C tenant. MSAL will fill the `username` field on the `AccountInfo` object with the first element of the array returned on the `emails` claim. In most cases this array will only have one element, however, if you notice that your idTokens are returning more than one email on this claim, ensure you are calling `getAccount({ username })` with the first email.

To enable this claim open up your User Flow configuration in the Azure Portal. Click the `User Attributes` tab and make sure `Email Address` is checked. Then click the `Application Claims` tab and make sure `Email Addresses` is checked. You can verify that the `emails` claim is now being returned by acquiring an `idToken` and inspecting its contents.

Expand Down
6 changes: 0 additions & 6 deletions lib/msal-browser/apiReview/msal-browser.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,12 +678,6 @@ export interface IController {
// (undocumented)
getAccount(accountFilter: AccountFilter): AccountInfo | null;
// (undocumented)
getAccountByHomeId(homeAccountId: string): AccountInfo | null;
// (undocumented)
getAccountByLocalId(localId: string): AccountInfo | null;
// (undocumented)
getAccountByUsername(userName: string): AccountInfo | null;
// (undocumented)
getActiveAccount(): AccountInfo | null;
// (undocumented)
getAllAccounts(accountFilter?: AccountFilter): AccountInfo[];
Expand Down
8 changes: 1 addition & 7 deletions lib/msal-browser/docs/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ The [AccountFilter](https://azuread.github.io/microsoft-authentication-library-f

> Note: `realm` is `tenantId` in the cache.

The following `getAccountBy` APIs are marked for deprecation and will be removed in a future version of MSAL. Please migrate to `getAccount()`:

- `getAccountByHomeId()`: receives a `homeAccountId` string and returns the matching account from the cache.
- `getAccountByLocalId()`: receives a `localAccountId` string and returns the matching account from the cache.
- `getAccountByUsername()`: receives a `username` string and returns the matching account from the cache.

The following is a usage examples that covers these APIs:

```javascript
Expand Down Expand Up @@ -165,7 +159,7 @@ For NAA applications, we consider `setActiveAccount()` and `getActiveAccount()`

- The current msal-browser default [sample](../../../samples/msal-browser-samples/VanillaJSTestApp2.0) has a working single account scenario.
- If you have a multiple accounts scenario, please modify the [sample](../../../samples/msal-browser-samples/VanillaJSTestApp2.0/app/default/auth.js) (in `handleResponse()`) to list all cached accounts and choose a specific account.
- If an application wants to retrieve an account based on the `username`, it needs to save the `username` (from the response of a `login` API for a specific user) prior to using `getAccountByUsername()` API.
- If an application wants to retrieve an account based on the `username`, it needs to save the `username` (from the response of a `login` API for a specific user) prior to using the `username` filter in the `getAccount()` API.
- `getAllAccounts()` will return multiple accounts if you have made several interactive token requests and the user has selected different accounts in two or more of those interactions. You may need to pass `prompt: "select_account"` or `prompt: "login"` to the interactive acquireToken or login API in order for AAD to display the account selection screen after the first interaction.
- The account APIs return local account state and do not necessarily reflect server state. They return accounts that have previously signed into this app using MSAL.js and the server session may or may not still be active.
- Two apps hosted on different domains do not share account state due to browser storage being segemented by domain.
Expand Down
2 changes: 1 addition & 1 deletion lib/msal-browser/docs/instance-aware.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function getGraphMeEndpoint(msGraphHost) {
}

async function seeProfile() {
const currentAcc = myMSALObj.getAccountByHomeId(accountId);
const currentAcc = myMSALObj.getAccount({ homeAccountId: accountId });
if (currentAcc) {
const response = await getTokenPopup(loginRequest, currentAcc).catch(error => {
console.log(error);
Expand Down
10 changes: 5 additions & 5 deletions lib/msal-browser/docs/login-user.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,19 @@ When a login call has succeeded, you can use the `getAllAccounts()` function to
const myAccounts: AccountInfo[] = msalInstance.getAllAccounts();
```

If you know the account information, you can also retrieve the account information by using the `getAccountByUsername()` or `getAccountByHomeId()` APIs:
If you know the account information, you can also retrieve the account information by using the `getAccount()` API:

```javascript
const username = "[email protected]";
const myAccount: AccountInfo = msalInstance.getAccountByUsername(username);
const myAccount: AccountInfo = msalInstance.getAccount({ username });

const homeAccountId = "userid.hometenantid"; // Best to retrieve the homeAccountId from an account object previously obtained through msal
const myAccount: AccountInfo = msalInstance.getAccountByHomeId(homeAccountId);
const myAccount: AccountInfo = msalInstance.getAccount({ homeAccountId });
```

**Note:** `getAccountByUsername()` is provided for convenience and should be considered less reliable than `getAccountByHomeId()`. When possible use `getAccountByHomeId()`.
**Note:** Filtering by `username` is provided for convenience and should be considered less reliable than searching based on `homeAccountId`. When possible use `homeAccountId`.

In B2C scenarios your B2C tenant will need to be configured to return the `emails` claim on `idTokens` in order to use the `getAccountByUsername()` API.
In B2C scenarios your B2C tenant will need to be configured to return the `emails` claim on `idTokens` in order to use the `username` filter on the `getAccount()` API.

These APIs will return an account object or an array of account objects with the following signature:

Expand Down
8 changes: 4 additions & 4 deletions lib/msal-browser/docs/logout.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Using `logoutRedirect` will clear local cache of user tokens then redirect the w
[Configuration options](https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_browser.html#endsessionrequest) can be provided to customize the behavior:

```javascript
const currentAccount = msalInstance.getAccountByHomeId(homeAccountId);
const currentAccount = msalInstance.getAccount({ homeAccountId });
await msalInstance.logoutRedirect({
account: currentAccount,
postLogoutRedirectUri: "https://contoso.com/loggedOut"
Expand Down Expand Up @@ -85,7 +85,7 @@ The `logoutPopup` API will open the server signout page in a popup, allowing you
[Configuration options](https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_browser.html#endsessionpopuprequest) can be provided to customize the behavior.

```javascript
const currentAccount = msalInstance.getAccountByHomeId(homeAccountId);
const currentAccount = msalInstance.getAccount({ homeAccountId });
await msalInstance.logoutPopup({
account: currentAccount,
postLogoutRedirectUri: "https://contoso.com/loggedOut",
Expand All @@ -112,7 +112,7 @@ If your client application has the [login_hint optional claim](https://docs.micr
The first and simplest option is to provide the account object you want to end the session for to the logout API. MSAL will check to see if the `login_hint` claim is available in the account's ID token and automatically add it to the end session request as `logout_hint` to skip the account picker prompt.

```javascript
const currentAccount = msalInstance.getAccountByHomeId(homeAccountId);
const currentAccount = msalInstance.getAccount({ homeAccountId });
// The account's ID Token must contain the login_hint optional claim to avoid the account picker
await msalInstance.logoutRedirect({ account: currentAccount});
```
Expand All @@ -122,7 +122,7 @@ await msalInstance.logoutRedirect({ account: currentAccount});
Alternatively, if you prefer to manually set the `logoutHint`, you can extract the `login_hint` claim in your app and set it as the `logoutHint` in the logout request:

```javascript
const currentAccount = msalInstance.getAccountByHomeId(homeAccountId);
const currentAccount = msalInstance.getAccount({ homeAccountId });

// Extract login hint to use as logout hint
const logoutHint = currentAccount.idTokenClaims.login_hint;
Expand Down
4 changes: 2 additions & 2 deletions lib/msal-browser/docs/token-lifetimes.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ A Cache Lookup Policy can be optionally provided to the request. The Cache Looku

```javascript
var username = "[email protected]";
var currentAccount = msalInstance.getAccountByUsername(username);
var currentAccount = msalInstance.getAccount({ username });
var silentRequest = {
scopes: ["Mail.Read"],
account: currentAccount,
Expand Down Expand Up @@ -115,7 +115,7 @@ const tokenResponse = await msalInstance.acquireTokenSilent(silentRequest).catch

```javascript
var username = "[email protected]";
var currentAccount = msalInstance.getAccountByUsername(username);
var currentAccount = msalInstance.getAccount({ username });
var silentRequest = {
scopes: ["Mail.Read"],
account: currentAccount,
Expand Down
112 changes: 0 additions & 112 deletions lib/msal-browser/src/cache/AccountManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,118 +51,6 @@ export function getAccount(
}
}

/**
* Returns the signed in account matching username.
* (the account object is created at the time of successful login)
* or null when no matching account is found.
* This API is provided for convenience but getAccountById should be used for best reliability
* @param username
* @returns The account object stored in MSAL
*/
export function getAccountByUsername(
username: string,
logger: Logger,
browserStorage: BrowserCacheManager
): AccountInfo | null {
logger.trace("getAccountByUsername called");
if (!username) {
logger.warning("getAccountByUsername: No username provided");
return null;
}

const account = browserStorage.getAccountInfoFilteredBy({
username,
});
if (account) {
logger.verbose(
"getAccountByUsername: Account matching username found, returning"
);
logger.verbosePii(
`getAccountByUsername: Returning signed-in accounts matching username: ${username}`
);
return account;
} else {
logger.verbose(
"getAccountByUsername: No matching account found, returning null"
);
return null;
}
}

/**
* Returns the signed in account matching homeAccountId.
* (the account object is created at the time of successful login)
* or null when no matching account is found
* @param homeAccountId
* @returns The account object stored in MSAL
*/
export function getAccountByHomeId(
homeAccountId: string,
logger: Logger,
browserStorage: BrowserCacheManager
): AccountInfo | null {
logger.trace("getAccountByHomeId called");
if (!homeAccountId) {
logger.warning("getAccountByHomeId: No homeAccountId provided");
return null;
}

const account = browserStorage.getAccountInfoFilteredBy({
homeAccountId,
});
if (account) {
logger.verbose(
"getAccountByHomeId: Account matching homeAccountId found, returning"
);
logger.verbosePii(
`getAccountByHomeId: Returning signed-in accounts matching homeAccountId: ${homeAccountId}`
);
return account;
} else {
logger.verbose(
"getAccountByHomeId: No matching account found, returning null"
);
return null;
}
}

/**
* Returns the signed in account matching localAccountId.
* (the account object is created at the time of successful login)
* or null when no matching account is found
* @param localAccountId
* @returns The account object stored in MSAL
*/
export function getAccountByLocalId(
localAccountId: string,
logger: Logger,
browserStorage: BrowserCacheManager
): AccountInfo | null {
logger.trace("getAccountByLocalId called");
if (!localAccountId) {
logger.warning("getAccountByLocalId: No localAccountId provided");
return null;
}

const account = browserStorage.getAccountInfoFilteredBy({
localAccountId,
});
if (account) {
logger.verbose(
"getAccountByLocalId: Account matching localAccountId found, returning"
);
logger.verbosePii(
`getAccountByLocalId: Returning signed-in accounts matching localAccountId: ${localAccountId}`
);
return account;
} else {
logger.verbose(
"getAccountByLocalId: No matching account found, returning null"
);
return null;
}
}

/**
* Sets the account to use as the active account. If no account is passed to the acquireToken APIs, then MSAL will use this active account.
* @param account
Expand Down
6 changes: 0 additions & 6 deletions lib/msal-browser/src/controllers/IController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ export interface IController {

getAccount(accountFilter: AccountFilter): AccountInfo | null;

getAccountByHomeId(homeAccountId: string): AccountInfo | null;

getAccountByLocalId(localId: string): AccountInfo | null;

getAccountByUsername(userName: string): AccountInfo | null;

getAllAccounts(accountFilter?: AccountFilter): AccountInfo[];

handleRedirectPromise(hash?: string): Promise<AuthenticationResult | null>;
Expand Down
46 changes: 0 additions & 46 deletions lib/msal-browser/src/controllers/NestedAppAuthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,52 +687,6 @@ export class NestedAppAuthController implements IController {
);
}

/**
* Returns the signed in account matching username.
* (the account object is created at the time of successful login)
* or null when no matching account is found.
* This API is provided for convenience but getAccountById should be used for best reliability
* @param username
* @returns The account object stored in MSAL
*/
getAccountByUsername(username: string): AccountInfo | null {
return AccountManager.getAccountByUsername(
username,
this.logger,
this.browserStorage
);
}

/**
* Returns the signed in account matching homeAccountId.
* (the account object is created at the time of successful login)
* or null when no matching account is found
* @param homeAccountId
* @returns The account object stored in MSAL
*/
getAccountByHomeId(homeAccountId: string): AccountInfo | null {
return AccountManager.getAccountByHomeId(
homeAccountId,
this.logger,
this.browserStorage
);
}

/**
* Returns the signed in account matching localAccountId.
* (the account object is created at the time of successful login)
* or null when no matching account is found
* @param localAccountId
* @returns The account object stored in MSAL
*/
getAccountByLocalId(localAccountId: string): AccountInfo | null {
return AccountManager.getAccountByLocalId(
localAccountId,
this.logger,
this.browserStorage
);
}

/**
* Sets the account to use as the active account. If no account is passed to the acquireToken APIs, then MSAL will use this active account.
* @param account
Expand Down
Loading
Loading