-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Supports caching in NAA apps (#7072)
NAA apps currently always request the bridge for tokens, adding load to the host caching hence blocking the deployment on scale. This PR adds support for: * Caching NAA app tokens (idToken and accessToken) in the naa app storage (based on `cacheConfig`) * Allows for NAA app to set `initContext` with `accountContext` to look for specific account in cache when available. MetaOS apps create and delete the NAA apps independent of the session. Hence, we always assume the Bridge will add the account context and only look for those tokens. If the account is not found, we always go for the hub to fetch tokens. **Minor additions:** * AccountManager created to not duplicate account lookup code and make them functions (saving size). * If a token is expired while cache lookup, it is cleaned. **Note and TBD:** Since there is no `logout` and naa app life cycle does not map to session life time, cache clean up is not comprehensive. However, this PR clears the cache when a token is identified as expired. The logout equivalent cache clearance (if the parent logs out, nested app should clean up cache) will be handled as a separate use case. --------- Co-authored-by: Thomas Norling <[email protected]>
- Loading branch information
Showing
17 changed files
with
837 additions
and
223 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
change/@azure-msal-browser-557666fc-3079-4825-873f-f2b27715aa76.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "minor", | ||
"comment": "Support cache in NAA apps #7072", | ||
"packageName": "@azure/msal-browser", | ||
"email": "[email protected]", | ||
"dependentChangeType": "patch" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { AccountInfo, AccountFilter, Logger } from "@azure/msal-common"; | ||
import { BrowserCacheManager } from "./BrowserCacheManager"; | ||
|
||
/** | ||
* Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned. | ||
* @param accountFilter - (Optional) filter to narrow down the accounts returned | ||
* @returns Array of AccountInfo objects in cache | ||
*/ | ||
export function getAllAccounts( | ||
logger: Logger, | ||
browserStorage: BrowserCacheManager, | ||
isInBrowser: boolean, | ||
accountFilter?: AccountFilter | ||
): AccountInfo[] { | ||
logger.verbose("getAllAccounts called"); | ||
return isInBrowser ? browserStorage.getAllAccounts(accountFilter) : []; | ||
} | ||
|
||
/** | ||
* Returns the first account found in the cache that matches the account filter passed in. | ||
* @param accountFilter | ||
* @returns The first account found in the cache matching the provided filter or null if no account could be found. | ||
*/ | ||
export function getAccount( | ||
accountFilter: AccountFilter, | ||
logger: Logger, | ||
browserStorage: BrowserCacheManager | ||
): AccountInfo | null { | ||
logger.trace("getAccount called"); | ||
if (Object.keys(accountFilter).length === 0) { | ||
logger.warning("getAccount: No accountFilter provided"); | ||
return null; | ||
} | ||
|
||
const account: AccountInfo | null = | ||
browserStorage.getAccountInfoFilteredBy(accountFilter); | ||
|
||
if (account) { | ||
logger.verbose( | ||
"getAccount: Account matching provided filter found, returning" | ||
); | ||
return account; | ||
} else { | ||
logger.verbose("getAccount: No matching account found, returning null"); | ||
return null; | ||
} | ||
} | ||
|
||
/** | ||
* 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 | ||
*/ | ||
export function setActiveAccount( | ||
account: AccountInfo | null, | ||
browserStorage: BrowserCacheManager | ||
): void { | ||
browserStorage.setActiveAccount(account); | ||
} | ||
|
||
/** | ||
* Gets the currently active account | ||
*/ | ||
export function getActiveAccount( | ||
browserStorage: BrowserCacheManager | ||
): AccountInfo | null { | ||
return browserStorage.getActiveAccount(); | ||
} |
Oops, something went wrong.