Skip to content

Commit 4730e0a

Browse files
tnorlingThomas NorlingCopilot
authored
Cache Rollback/Upgrade support (#7957)
Updates caching layer to version entries and allow caches from multiple versions to co-exist for a short period of time. This is done to better support rolling back to an older version --------- Co-authored-by: Thomas Norling <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent bd49c2d commit 4730e0a

File tree

75 files changed

+3084
-1114
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+3084
-1114
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Cache upgrade & rollback support",
4+
"packageName": "@azure/msal-browser",
5+
"email": "[email protected]",
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": "minor",
3+
"comment": "Cache upgrade & rollback support",
4+
"packageName": "@azure/msal-common",
5+
"email": "[email protected]",
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": "minor",
3+
"comment": "Update internal cache key generation",
4+
"packageName": "@azure/msal-node",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ export type CacheLookupPolicy = (typeof CacheLookupPolicy)[keyof typeof CacheLoo
636636
// @public
637637
export type CacheOptions = {
638638
cacheLocation?: BrowserCacheLocation | string;
639+
cacheRetentionDays?: number;
639640
temporaryCacheLocation?: BrowserCacheLocation | string;
640641
storeAuthStateInCookie?: boolean;
641642
secureCookies?: boolean;
@@ -1172,6 +1173,10 @@ export interface ITokenCache {
11721173
export interface IWindowStorage<T> {
11731174
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
11741175
containsKey(key: string): boolean;
1176+
// Warning: (ae-forgotten-export) The symbol "EncryptedData" needs to be exported by the entry point index.d.ts
1177+
//
1178+
// (undocumented)
1179+
decryptData(key: string, data: EncryptedData, correlationId: string): Promise<object | null>;
11751180
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
11761181
getItem(key: string): T | null;
11771182
getKeys(): string[];
@@ -1205,6 +1210,8 @@ export class LocalStorage implements IWindowStorage<string> {
12051210
// (undocumented)
12061211
containsKey(key: string): boolean;
12071212
// (undocumented)
1213+
decryptData(key: string, data: EncryptedData, correlationId: string): Promise<object | null>;
1214+
// (undocumented)
12081215
getItem(key: string): string | null;
12091216
// (undocumented)
12101217
getKeys(): string[];
@@ -1234,6 +1241,8 @@ export class MemoryStorage<T> implements IWindowStorage<T> {
12341241
// (undocumented)
12351242
containsKey(key: string): boolean;
12361243
// (undocumented)
1244+
decryptData(): Promise<object | null>;
1245+
// (undocumented)
12371246
getItem(key: string): T | null;
12381247
// (undocumented)
12391248
getKeys(): string[];
@@ -1642,6 +1651,8 @@ export class SessionStorage implements IWindowStorage<string> {
16421651
// (undocumented)
16431652
containsKey(key: string): boolean;
16441653
// (undocumented)
1654+
decryptData(): Promise<object | null>;
1655+
// (undocumented)
16451656
getItem(key: string): string | null;
16461657
// (undocumented)
16471658
getKeys(): string[];
@@ -1806,10 +1817,10 @@ export type WrapperSKU = (typeof WrapperSKU)[keyof typeof WrapperSKU];
18061817
// src/app/PublicClientNext.ts:85:79 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
18071818
// src/app/PublicClientNext.ts:88:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
18081819
// src/app/PublicClientNext.ts:89:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1809-
// src/cache/LocalStorage.ts:299:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1810-
// src/cache/LocalStorage.ts:357:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1811-
// src/cache/LocalStorage.ts:388:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1812-
// src/config/Configuration.ts:256:5 - (ae-forgotten-export) The symbol "InternalAuthOptions" needs to be exported by the entry point index.d.ts
1820+
// src/cache/LocalStorage.ts:355:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1821+
// src/cache/LocalStorage.ts:413:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1822+
// src/cache/LocalStorage.ts:444:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
1823+
// src/config/Configuration.ts:260:5 - (ae-forgotten-export) The symbol "InternalAuthOptions" needs to be exported by the entry point index.d.ts
18131824
// src/event/EventHandler.ts:113:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
18141825
// src/event/EventHandler.ts:139:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
18151826
// 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/caching.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,31 @@ When using MSAL.js with the default configuration in a scenario where the user i
8080

8181
To handle this scenario, you can configure MSAL to use `localStorage` as the cache location by overriding the `temporaryCacheLocation` configuration property. This allows the code verifier and challenge to be stored in the browser's `localStorage,` which is persistent across multiple tabs and windows.
8282

83+
## Cache persistence during MSAL.js upgrades and rollbacks
84+
85+
Occasionally MSAL.js needs to make changes to the shape of the cached artifacts to support new requirements, features or bug fixes. As often as possible these changes will be made in a backwards compatible way so as to ensure that when an application upgrades to a new version or rolls back to an older one the cache present in a user's browser can still be used. However, this is not always possible and you may end up in a state where multiple copies of the cache exist concurrently, one used by the current version of MSAL.js running and another that was written by the version used prior to the upgrade. This is done to allow applications to gracefully rollback, if needed. In the vast majority of upgrades, MSAL.js will migrate any existing cache into the new format for a seamless upgrade experience. In rare cases, such as the upgrade from v3 to v4, this may not be possible due to security or privacy requirements and this will always result in a major version bump.
86+
87+
When a breaking cache change is made the older cache will be kept for 5 days, by default, to allow for a rollback if needed. The length of time old cache is kept can be configured using the `cacheRetentionDays` cache configuration on `PublicClientApplication`. If the cache has not been actively used within that time it will be cleared the next time MSAL.js is initialized. Additionally, if you do not anticipate needing to rollback you may set this value to `0` to indicate that old cache should always be removed immediately upon upgrading to a new version of MSAL.js. Conversely, if you have a longer rollout window for upgrades you may choose to set this to a longer value.
88+
89+
> [!NOTE]
90+
> Access and Refresh tokens will be removed once they have expired, even if the configured `cacheRetentionDays` has not yet been reached.
91+
> Valid access tokens may also be removed at any time if browser storage reaches its storage quota. When storage quotas are reached access tokens will be removed on a First In First Out basis, starting with entries written by a previous version of MSAL.js and then moving on to entries written by the current version of MSAL.js.
92+
93+
```javascript
94+
const config = {
95+
auth: {
96+
clientId: "<your-client-id>"
97+
},
98+
cache: {
99+
cacheLocation: "localStorage",
100+
cacheRetentionDays: 0 // Set this to the number of days you want old cache to be preserved in the event a rollback is needed (Default 5 days)
101+
}
102+
}
103+
104+
const pca = new PublicClientApplication(config);
105+
await pca.initialize();
106+
```
107+
83108
## Remarks
84109

85110
- We do not recommend apps having business logic dependent on direct use of entities in the cache. Instead, use the appropriate MSAL API when you need to acquire tokens or retrieve accounts.

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ import { PlatformAuthExtensionHandler } from "./PlatformAuthExtensionHandler.js"
1919
import { IPlatformAuthHandler } from "./IPlatformAuthHandler.js";
2020
import { PlatformAuthDOMHandler } from "./PlatformAuthDOMHandler.js";
2121
import { createNewGuid } from "../../crypto/BrowserCrypto.js";
22-
import {
23-
BrowserCacheLocation,
24-
PLATFORM_AUTH_DOM_SUPPORT,
25-
} from "../../utils/BrowserConstants.js";
22+
import { BrowserCacheLocation } from "../../utils/BrowserConstants.js";
23+
import { PLATFORM_AUTH_DOM_SUPPORT } from "../../cache/CacheKeys.js";
2624

2725
/**
2826
* Checks if the platform broker is available in the current environment.

0 commit comments

Comments
 (0)