@azure/msal-browser 3.28.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/dist/app/IPublicClientApplication.mjs +1 -1
  2. package/dist/app/PublicClientApplication.mjs +1 -1
  3. package/dist/app/PublicClientNext.mjs +1 -1
  4. package/dist/broker/nativeBroker/NativeMessageHandler.d.ts +1 -1
  5. package/dist/broker/nativeBroker/NativeMessageHandler.d.ts.map +1 -1
  6. package/dist/broker/nativeBroker/NativeMessageHandler.mjs +8 -8
  7. package/dist/broker/nativeBroker/NativeMessageHandler.mjs.map +1 -1
  8. package/dist/broker/nativeBroker/NativeResponse.d.ts +1 -1
  9. package/dist/broker/nativeBroker/NativeStatusCodes.mjs +1 -1
  10. package/dist/cache/AccountManager.mjs +1 -1
  11. package/dist/cache/AsyncMemoryStorage.mjs +1 -1
  12. package/dist/cache/BrowserCacheManager.d.ts +11 -51
  13. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  14. package/dist/cache/BrowserCacheManager.mjs +42 -291
  15. package/dist/cache/BrowserCacheManager.mjs.map +1 -1
  16. package/dist/cache/CacheHelpers.d.ts +16 -0
  17. package/dist/cache/CacheHelpers.d.ts.map +1 -0
  18. package/dist/cache/CacheHelpers.mjs +46 -0
  19. package/dist/cache/CacheHelpers.mjs.map +1 -0
  20. package/dist/cache/CookieStorage.d.ts +3 -0
  21. package/dist/cache/CookieStorage.d.ts.map +1 -1
  22. package/dist/cache/CookieStorage.mjs +12 -1
  23. package/dist/cache/CookieStorage.mjs.map +1 -1
  24. package/dist/cache/DatabaseStorage.mjs +1 -1
  25. package/dist/cache/ITokenCache.d.ts +1 -1
  26. package/dist/cache/ITokenCache.d.ts.map +1 -1
  27. package/dist/cache/IWindowStorage.d.ts +12 -0
  28. package/dist/cache/IWindowStorage.d.ts.map +1 -1
  29. package/dist/cache/LocalStorage.d.ts +38 -1
  30. package/dist/cache/LocalStorage.d.ts.map +1 -1
  31. package/dist/cache/LocalStorage.mjs +183 -2
  32. package/dist/cache/LocalStorage.mjs.map +1 -1
  33. package/dist/cache/MemoryStorage.d.ts +3 -0
  34. package/dist/cache/MemoryStorage.d.ts.map +1 -1
  35. package/dist/cache/MemoryStorage.mjs +10 -1
  36. package/dist/cache/MemoryStorage.mjs.map +1 -1
  37. package/dist/cache/SessionStorage.d.ts +3 -0
  38. package/dist/cache/SessionStorage.d.ts.map +1 -1
  39. package/dist/cache/SessionStorage.mjs +10 -1
  40. package/dist/cache/SessionStorage.mjs.map +1 -1
  41. package/dist/cache/TokenCache.d.ts +1 -1
  42. package/dist/cache/TokenCache.d.ts.map +1 -1
  43. package/dist/cache/TokenCache.mjs +16 -15
  44. package/dist/cache/TokenCache.mjs.map +1 -1
  45. package/dist/config/Configuration.d.ts +2 -2
  46. package/dist/config/Configuration.d.ts.map +1 -1
  47. package/dist/config/Configuration.mjs +5 -5
  48. package/dist/config/Configuration.mjs.map +1 -1
  49. package/dist/controllers/ControllerFactory.mjs +1 -1
  50. package/dist/controllers/NestedAppAuthController.d.ts +4 -3
  51. package/dist/controllers/NestedAppAuthController.d.ts.map +1 -1
  52. package/dist/controllers/NestedAppAuthController.mjs +8 -6
  53. package/dist/controllers/NestedAppAuthController.mjs.map +1 -1
  54. package/dist/controllers/StandardController.d.ts +2 -2
  55. package/dist/controllers/StandardController.d.ts.map +1 -1
  56. package/dist/controllers/StandardController.mjs +27 -22
  57. package/dist/controllers/StandardController.mjs.map +1 -1
  58. package/dist/controllers/UnknownOperatingContextController.d.ts +2 -2
  59. package/dist/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  60. package/dist/controllers/UnknownOperatingContextController.mjs +3 -3
  61. package/dist/controllers/UnknownOperatingContextController.mjs.map +1 -1
  62. package/dist/crypto/BrowserCrypto.d.ts +27 -0
  63. package/dist/crypto/BrowserCrypto.d.ts.map +1 -1
  64. package/dist/crypto/BrowserCrypto.mjs +83 -3
  65. package/dist/crypto/BrowserCrypto.mjs.map +1 -1
  66. package/dist/crypto/CryptoOps.mjs +1 -1
  67. package/dist/crypto/PkceGenerator.mjs +1 -1
  68. package/dist/crypto/SignedHttpRequest.mjs +1 -1
  69. package/dist/encode/Base64Decode.d.ts +5 -0
  70. package/dist/encode/Base64Decode.d.ts.map +1 -1
  71. package/dist/encode/Base64Decode.mjs +2 -2
  72. package/dist/encode/Base64Decode.mjs.map +1 -1
  73. package/dist/encode/Base64Encode.mjs +1 -1
  74. package/dist/error/BrowserAuthError.mjs +1 -1
  75. package/dist/error/BrowserAuthErrorCodes.mjs +1 -1
  76. package/dist/error/BrowserConfigurationAuthError.mjs +1 -1
  77. package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +1 -1
  78. package/dist/error/NativeAuthError.mjs +1 -1
  79. package/dist/error/NativeAuthError.mjs.map +1 -1
  80. package/dist/error/NativeAuthErrorCodes.mjs +1 -1
  81. package/dist/error/NestedAppAuthError.mjs +1 -1
  82. package/dist/event/EventHandler.mjs +1 -1
  83. package/dist/event/EventMessage.mjs +1 -1
  84. package/dist/event/EventType.mjs +1 -1
  85. package/dist/index.d.ts +0 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.mjs +1 -2
  88. package/dist/index.mjs.map +1 -1
  89. package/dist/interaction_client/BaseInteractionClient.mjs +1 -1
  90. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
  91. package/dist/interaction_client/NativeInteractionClient.d.ts +2 -2
  92. package/dist/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  93. package/dist/interaction_client/NativeInteractionClient.mjs +6 -6
  94. package/dist/interaction_client/NativeInteractionClient.mjs.map +1 -1
  95. package/dist/interaction_client/PopupClient.d.ts.map +1 -1
  96. package/dist/interaction_client/PopupClient.mjs +4 -4
  97. package/dist/interaction_client/PopupClient.mjs.map +1 -1
  98. package/dist/interaction_client/RedirectClient.mjs +2 -2
  99. package/dist/interaction_client/RedirectClient.mjs.map +1 -1
  100. package/dist/interaction_client/SilentAuthCodeClient.mjs +1 -1
  101. package/dist/interaction_client/SilentCacheClient.mjs +1 -1
  102. package/dist/interaction_client/SilentIframeClient.mjs +2 -2
  103. package/dist/interaction_client/SilentIframeClient.mjs.map +1 -1
  104. package/dist/interaction_client/SilentRefreshClient.mjs +1 -1
  105. package/dist/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  106. package/dist/interaction_client/StandardInteractionClient.mjs +1 -8
  107. package/dist/interaction_client/StandardInteractionClient.mjs.map +1 -1
  108. package/dist/interaction_handler/InteractionHandler.mjs +1 -1
  109. package/dist/interaction_handler/RedirectHandler.mjs +1 -1
  110. package/dist/interaction_handler/SilentHandler.mjs +1 -1
  111. package/dist/naa/BridgeError.mjs +1 -1
  112. package/dist/naa/BridgeProxy.mjs +1 -1
  113. package/dist/naa/BridgeStatusCode.mjs +1 -1
  114. package/dist/naa/mapping/NestedAppAuthAdapter.mjs +1 -1
  115. package/dist/navigation/NavigationClient.mjs +1 -1
  116. package/dist/network/FetchClient.mjs +1 -1
  117. package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
  118. package/dist/operatingcontext/NestedAppOperatingContext.mjs +1 -1
  119. package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
  120. package/dist/operatingcontext/UnknownOperatingContext.mjs +1 -1
  121. package/dist/packageMetadata.d.ts +1 -1
  122. package/dist/packageMetadata.d.ts.map +1 -1
  123. package/dist/packageMetadata.mjs +2 -2
  124. package/dist/request/AuthorizationUrlRequest.d.ts +1 -1
  125. package/dist/request/AuthorizationUrlRequest.d.ts.map +1 -1
  126. package/dist/request/PopupRequest.d.ts +1 -1
  127. package/dist/request/PopupRequest.d.ts.map +1 -1
  128. package/dist/request/RedirectRequest.d.ts +1 -1
  129. package/dist/request/RedirectRequest.d.ts.map +1 -1
  130. package/dist/request/RequestHelpers.mjs +1 -1
  131. package/dist/request/SsoSilentRequest.d.ts +1 -1
  132. package/dist/request/SsoSilentRequest.d.ts.map +1 -1
  133. package/dist/response/ResponseHandler.mjs +1 -1
  134. package/dist/telemetry/BrowserPerformanceClient.mjs +1 -1
  135. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
  136. package/dist/utils/BrowserConstants.mjs +1 -1
  137. package/dist/utils/BrowserProtocolUtils.mjs +1 -1
  138. package/dist/utils/BrowserUtils.mjs +1 -1
  139. package/lib/msal-browser.cjs +630 -650
  140. package/lib/msal-browser.cjs.map +1 -1
  141. package/lib/msal-browser.js +630 -650
  142. package/lib/msal-browser.js.map +1 -1
  143. package/lib/msal-browser.min.js +65 -66
  144. package/lib/types/broker/nativeBroker/NativeMessageHandler.d.ts +1 -1
  145. package/lib/types/broker/nativeBroker/NativeMessageHandler.d.ts.map +1 -1
  146. package/lib/types/broker/nativeBroker/NativeResponse.d.ts +1 -1
  147. package/lib/types/cache/BrowserCacheManager.d.ts +11 -51
  148. package/lib/types/cache/BrowserCacheManager.d.ts.map +1 -1
  149. package/lib/types/cache/CacheHelpers.d.ts +16 -0
  150. package/lib/types/cache/CacheHelpers.d.ts.map +1 -0
  151. package/lib/types/cache/CookieStorage.d.ts +3 -0
  152. package/lib/types/cache/CookieStorage.d.ts.map +1 -1
  153. package/lib/types/cache/ITokenCache.d.ts +1 -1
  154. package/lib/types/cache/ITokenCache.d.ts.map +1 -1
  155. package/lib/types/cache/IWindowStorage.d.ts +12 -0
  156. package/lib/types/cache/IWindowStorage.d.ts.map +1 -1
  157. package/lib/types/cache/LocalStorage.d.ts +38 -1
  158. package/lib/types/cache/LocalStorage.d.ts.map +1 -1
  159. package/lib/types/cache/MemoryStorage.d.ts +3 -0
  160. package/lib/types/cache/MemoryStorage.d.ts.map +1 -1
  161. package/lib/types/cache/SessionStorage.d.ts +3 -0
  162. package/lib/types/cache/SessionStorage.d.ts.map +1 -1
  163. package/lib/types/cache/TokenCache.d.ts +1 -1
  164. package/lib/types/cache/TokenCache.d.ts.map +1 -1
  165. package/lib/types/config/Configuration.d.ts +2 -2
  166. package/lib/types/config/Configuration.d.ts.map +1 -1
  167. package/lib/types/controllers/NestedAppAuthController.d.ts +4 -3
  168. package/lib/types/controllers/NestedAppAuthController.d.ts.map +1 -1
  169. package/lib/types/controllers/StandardController.d.ts +2 -2
  170. package/lib/types/controllers/StandardController.d.ts.map +1 -1
  171. package/lib/types/controllers/UnknownOperatingContextController.d.ts +2 -2
  172. package/lib/types/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  173. package/lib/types/crypto/BrowserCrypto.d.ts +27 -0
  174. package/lib/types/crypto/BrowserCrypto.d.ts.map +1 -1
  175. package/lib/types/encode/Base64Decode.d.ts +5 -0
  176. package/lib/types/encode/Base64Decode.d.ts.map +1 -1
  177. package/lib/types/index.d.ts +0 -1
  178. package/lib/types/index.d.ts.map +1 -1
  179. package/lib/types/interaction_client/NativeInteractionClient.d.ts +2 -2
  180. package/lib/types/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  181. package/lib/types/interaction_client/PopupClient.d.ts.map +1 -1
  182. package/lib/types/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  183. package/lib/types/packageMetadata.d.ts +1 -1
  184. package/lib/types/packageMetadata.d.ts.map +1 -1
  185. package/lib/types/request/AuthorizationUrlRequest.d.ts +1 -1
  186. package/lib/types/request/AuthorizationUrlRequest.d.ts.map +1 -1
  187. package/lib/types/request/PopupRequest.d.ts +1 -1
  188. package/lib/types/request/PopupRequest.d.ts.map +1 -1
  189. package/lib/types/request/RedirectRequest.d.ts +1 -1
  190. package/lib/types/request/RedirectRequest.d.ts.map +1 -1
  191. package/lib/types/request/SsoSilentRequest.d.ts +1 -1
  192. package/lib/types/request/SsoSilentRequest.d.ts.map +1 -1
  193. package/package.json +2 -2
  194. package/src/broker/nativeBroker/NativeMessageHandler.ts +7 -7
  195. package/src/broker/nativeBroker/NativeResponse.ts +1 -1
  196. package/src/cache/BrowserCacheManager.ts +95 -422
  197. package/src/cache/CacheHelpers.ts +52 -0
  198. package/src/cache/CookieStorage.ts +18 -0
  199. package/src/cache/ITokenCache.ts +1 -1
  200. package/src/cache/IWindowStorage.ts +14 -0
  201. package/src/cache/LocalStorage.ts +330 -1
  202. package/src/cache/MemoryStorage.ts +12 -0
  203. package/src/cache/SessionStorage.ts +12 -0
  204. package/src/cache/TokenCache.ts +42 -25
  205. package/src/config/Configuration.ts +6 -6
  206. package/src/controllers/NestedAppAuthController.ts +14 -6
  207. package/src/controllers/StandardController.ts +41 -22
  208. package/src/controllers/UnknownOperatingContextController.ts +6 -5
  209. package/src/crypto/BrowserCrypto.ts +120 -1
  210. package/src/encode/Base64Decode.ts +1 -1
  211. package/src/index.ts +0 -1
  212. package/src/interaction_client/NativeInteractionClient.ts +7 -6
  213. package/src/interaction_client/PopupClient.ts +9 -8
  214. package/src/interaction_client/RedirectClient.ts +1 -1
  215. package/src/interaction_client/SilentIframeClient.ts +1 -1
  216. package/src/interaction_client/StandardInteractionClient.ts +0 -8
  217. package/src/packageMetadata.ts +1 -1
  218. package/src/request/AuthorizationUrlRequest.ts +1 -1
  219. package/src/request/PopupRequest.ts +1 -1
  220. package/src/request/RedirectRequest.ts +1 -1
  221. package/src/request/SsoSilentRequest.ts +1 -1
  222. package/dist/cache/BrowserStorage.d.ts +0 -14
  223. package/dist/cache/BrowserStorage.d.ts.map +0 -1
  224. package/dist/cache/BrowserStorage.mjs +0 -46
  225. package/dist/cache/BrowserStorage.mjs.map +0 -1
  226. package/lib/types/cache/BrowserStorage.d.ts +0 -14
  227. package/lib/types/cache/BrowserStorage.d.ts.map +0 -1
  228. package/src/cache/BrowserStorage.ts +0 -52
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { TokenKeys } from "@azure/msal-common/browser";
7
+ import { StaticCacheKeys } from "../utils/BrowserConstants.js";
8
+ import { IWindowStorage } from "./IWindowStorage.js";
9
+
10
+ /**
11
+ * Returns a list of cache keys for all known accounts
12
+ * @param storage
13
+ * @returns
14
+ */
15
+ export function getAccountKeys(storage: IWindowStorage<string>): Array<string> {
16
+ const accountKeys = storage.getItem(StaticCacheKeys.ACCOUNT_KEYS);
17
+ if (accountKeys) {
18
+ return JSON.parse(accountKeys);
19
+ }
20
+
21
+ return [];
22
+ }
23
+
24
+ /**
25
+ * Returns a list of cache keys for all known tokens
26
+ * @param clientId
27
+ * @param storage
28
+ * @returns
29
+ */
30
+ export function getTokenKeys(
31
+ clientId: string,
32
+ storage: IWindowStorage<string>
33
+ ): TokenKeys {
34
+ const item = storage.getItem(`${StaticCacheKeys.TOKEN_KEYS}.${clientId}`);
35
+ if (item) {
36
+ const tokenKeys = JSON.parse(item);
37
+ if (
38
+ tokenKeys &&
39
+ tokenKeys.hasOwnProperty("idToken") &&
40
+ tokenKeys.hasOwnProperty("accessToken") &&
41
+ tokenKeys.hasOwnProperty("refreshToken")
42
+ ) {
43
+ return tokenKeys as TokenKeys;
44
+ }
45
+ }
46
+
47
+ return {
48
+ idToken: [],
49
+ accessToken: [],
50
+ refreshToken: [],
51
+ };
52
+ }
@@ -3,12 +3,20 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ import {
7
+ ClientAuthErrorCodes,
8
+ createClientAuthError,
9
+ } from "@azure/msal-common/browser";
6
10
  import { IWindowStorage } from "./IWindowStorage.js";
7
11
 
8
12
  // Cookie life calculation (hours * minutes * seconds * ms)
9
13
  const COOKIE_LIFE_MULTIPLIER = 24 * 60 * 60 * 1000;
10
14
 
11
15
  export class CookieStorage implements IWindowStorage<string> {
16
+ initialize(): Promise<void> {
17
+ return Promise.resolve();
18
+ }
19
+
12
20
  getItem(key: string): string | null {
13
21
  const name = `${encodeURIComponent(key)}`;
14
22
  const cookieList = document.cookie.split(";");
@@ -24,6 +32,10 @@ export class CookieStorage implements IWindowStorage<string> {
24
32
  return "";
25
33
  }
26
34
 
35
+ getUserData(): string | null {
36
+ throw createClientAuthError(ClientAuthErrorCodes.methodNotImplemented);
37
+ }
38
+
27
39
  setItem(
28
40
  key: string,
29
41
  value: string,
@@ -46,6 +58,12 @@ export class CookieStorage implements IWindowStorage<string> {
46
58
  document.cookie = cookieStr;
47
59
  }
48
60
 
61
+ async setUserData(): Promise<void> {
62
+ return Promise.reject(
63
+ createClientAuthError(ClientAuthErrorCodes.methodNotImplemented)
64
+ );
65
+ }
66
+
49
67
  removeItem(key: string): void {
50
68
  // Setting expiration to -1 removes it
51
69
  this.setItem(key, "", -1);
@@ -17,5 +17,5 @@ export interface ITokenCache {
17
17
  request: SilentRequest,
18
18
  response: ExternalTokenResponse,
19
19
  options: LoadTokenOptions
20
- ): AuthenticationResult;
20
+ ): Promise<AuthenticationResult>;
21
21
  }
@@ -4,12 +4,21 @@
4
4
  */
5
5
 
6
6
  export interface IWindowStorage<T> {
7
+ /**
8
+ * Async initializer
9
+ */
10
+ initialize(correlationId: string): Promise<void>;
7
11
  /**
8
12
  * Get the item from the window storage object matching the given key.
9
13
  * @param key
10
14
  */
11
15
  getItem(key: string): T | null;
12
16
 
17
+ /**
18
+ * Getter for sensitive data that may contain PII.
19
+ */
20
+ getUserData(key: string): T | null;
21
+
13
22
  /**
14
23
  * Sets the item in the window storage object with the given key.
15
24
  * @param key
@@ -17,6 +26,11 @@ export interface IWindowStorage<T> {
17
26
  */
18
27
  setItem(key: string, value: T): void;
19
28
 
29
+ /**
30
+ * Setter for sensitive data that may contain PII.
31
+ */
32
+ setUserData(key: string, value: T, correlationId: string): Promise<void>;
33
+
20
34
  /**
21
35
  * Removes the item in the window storage object matching the given key.
22
36
  * @param key
@@ -3,30 +3,197 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ import {
7
+ Constants,
8
+ TokenKeys,
9
+ IPerformanceClient,
10
+ invokeAsync,
11
+ PerformanceEvents,
12
+ Logger,
13
+ invoke,
14
+ } from "@azure/msal-common/browser";
15
+ import {
16
+ createNewGuid,
17
+ decrypt,
18
+ encrypt,
19
+ generateBaseKey,
20
+ generateHKDF,
21
+ } from "../crypto/BrowserCrypto.js";
22
+ import { base64DecToArr } from "../encode/Base64Decode.js";
23
+ import { urlEncodeArr } from "../encode/Base64Encode.js";
24
+ import {
25
+ BrowserAuthErrorCodes,
26
+ createBrowserAuthError,
27
+ } from "../error/BrowserAuthError.js";
6
28
  import {
7
29
  BrowserConfigurationAuthErrorCodes,
8
30
  createBrowserConfigurationAuthError,
9
31
  } from "../error/BrowserConfigurationAuthError.js";
32
+ import { CookieStorage } from "./CookieStorage.js";
10
33
  import { IWindowStorage } from "./IWindowStorage.js";
34
+ import { MemoryStorage } from "./MemoryStorage.js";
35
+ import { getAccountKeys, getTokenKeys } from "./CacheHelpers.js";
36
+ import { StaticCacheKeys } from "../utils/BrowserConstants.js";
37
+
38
+ const ENCRYPTION_KEY = "msal.cache.encryption";
39
+
40
+ type EncryptionCookie = {
41
+ id: string;
42
+ key: CryptoKey;
43
+ };
44
+
45
+ type EncryptedData = {
46
+ id: string;
47
+ nonce: string;
48
+ data: string;
49
+ };
11
50
 
12
51
  export class LocalStorage implements IWindowStorage<string> {
13
- constructor() {
52
+ private clientId: string;
53
+ private initialized: boolean;
54
+ private memoryStorage: MemoryStorage<string>;
55
+ private performanceClient: IPerformanceClient;
56
+ private logger: Logger;
57
+ private encryptionCookie?: EncryptionCookie;
58
+
59
+ constructor(
60
+ clientId: string,
61
+ logger: Logger,
62
+ performanceClient: IPerformanceClient
63
+ ) {
14
64
  if (!window.localStorage) {
15
65
  throw createBrowserConfigurationAuthError(
16
66
  BrowserConfigurationAuthErrorCodes.storageNotSupported
17
67
  );
18
68
  }
69
+ this.memoryStorage = new MemoryStorage<string>();
70
+ this.initialized = false;
71
+ this.clientId = clientId;
72
+ this.logger = logger;
73
+ this.performanceClient = performanceClient;
74
+ }
75
+
76
+ async initialize(correlationId: string): Promise<void> {
77
+ this.initialized = true;
78
+
79
+ const cookies = new CookieStorage();
80
+ const cookieString = cookies.getItem(ENCRYPTION_KEY);
81
+ let parsedCookie = { key: "", id: "" };
82
+ if (cookieString) {
83
+ try {
84
+ parsedCookie = JSON.parse(cookieString);
85
+ } catch (e) {}
86
+ }
87
+ if (parsedCookie.key && parsedCookie.id) {
88
+ // Encryption key already exists, import
89
+ const baseKey = invoke(
90
+ base64DecToArr,
91
+ PerformanceEvents.Base64Decode,
92
+ this.logger,
93
+ this.performanceClient,
94
+ correlationId
95
+ )(parsedCookie.key);
96
+ this.encryptionCookie = {
97
+ id: parsedCookie.id,
98
+ key: await invokeAsync(
99
+ generateHKDF,
100
+ PerformanceEvents.GenerateHKDF,
101
+ this.logger,
102
+ this.performanceClient,
103
+ correlationId
104
+ )(baseKey),
105
+ };
106
+ await invokeAsync(
107
+ this.importExistingCache.bind(this),
108
+ PerformanceEvents.ImportExistingCache,
109
+ this.logger,
110
+ this.performanceClient,
111
+ correlationId
112
+ )(correlationId);
113
+ } else {
114
+ // Encryption key doesn't exist or is invalid, generate a new one and clear existing cache
115
+ this.clear();
116
+ const id = createNewGuid();
117
+ const baseKey = await invokeAsync(
118
+ generateBaseKey,
119
+ PerformanceEvents.GenerateBaseKey,
120
+ this.logger,
121
+ this.performanceClient,
122
+ correlationId
123
+ )();
124
+ const keyStr = invoke(
125
+ urlEncodeArr,
126
+ PerformanceEvents.UrlEncodeArr,
127
+ this.logger,
128
+ this.performanceClient,
129
+ correlationId
130
+ )(new Uint8Array(baseKey));
131
+ this.encryptionCookie = {
132
+ id: id,
133
+ key: await invokeAsync(
134
+ generateHKDF,
135
+ PerformanceEvents.GenerateHKDF,
136
+ this.logger,
137
+ this.performanceClient,
138
+ correlationId
139
+ )(baseKey),
140
+ };
141
+
142
+ const cookieData = {
143
+ id: id,
144
+ key: keyStr,
145
+ };
146
+ cookies.setItem(ENCRYPTION_KEY, JSON.stringify(cookieData));
147
+ }
19
148
  }
20
149
 
21
150
  getItem(key: string): string | null {
22
151
  return window.localStorage.getItem(key);
23
152
  }
24
153
 
154
+ getUserData(key: string): string | null {
155
+ if (!this.initialized) {
156
+ throw createBrowserAuthError(
157
+ BrowserAuthErrorCodes.uninitializedPublicClientApplication
158
+ );
159
+ }
160
+ return this.memoryStorage.getItem(key);
161
+ }
162
+
25
163
  setItem(key: string, value: string): void {
26
164
  window.localStorage.setItem(key, value);
27
165
  }
28
166
 
167
+ async setUserData(
168
+ key: string,
169
+ value: string,
170
+ correlationId: string
171
+ ): Promise<void> {
172
+ if (!this.initialized || !this.encryptionCookie) {
173
+ throw createBrowserAuthError(
174
+ BrowserAuthErrorCodes.uninitializedPublicClientApplication
175
+ );
176
+ }
177
+
178
+ const { data, nonce } = await invokeAsync(
179
+ encrypt,
180
+ PerformanceEvents.Encrypt,
181
+ this.logger,
182
+ this.performanceClient,
183
+ correlationId
184
+ )(this.encryptionCookie.key, value, this.getContext(key));
185
+ const encryptedData: EncryptedData = {
186
+ id: this.encryptionCookie.id,
187
+ nonce: nonce,
188
+ data: data,
189
+ };
190
+
191
+ this.memoryStorage.setItem(key, value);
192
+ this.setItem(key, JSON.stringify(encryptedData));
193
+ }
194
+
29
195
  removeItem(key: string): void {
196
+ this.memoryStorage.removeItem(key);
30
197
  window.localStorage.removeItem(key);
31
198
  }
32
199
 
@@ -37,4 +204,166 @@ export class LocalStorage implements IWindowStorage<string> {
37
204
  containsKey(key: string): boolean {
38
205
  return window.localStorage.hasOwnProperty(key);
39
206
  }
207
+
208
+ /**
209
+ * Removes all known MSAL keys from the cache
210
+ */
211
+ clear(): void {
212
+ // Removes all remaining MSAL cache items
213
+ this.memoryStorage.clear();
214
+
215
+ const accountKeys = getAccountKeys(this);
216
+ accountKeys.forEach((key) => this.removeItem(key));
217
+ const tokenKeys = getTokenKeys(this.clientId, this);
218
+ tokenKeys.idToken.forEach((key) => this.removeItem(key));
219
+ tokenKeys.accessToken.forEach((key) => this.removeItem(key));
220
+ tokenKeys.refreshToken.forEach((key) => this.removeItem(key));
221
+
222
+ // Clean up anything left
223
+ this.getKeys().forEach((cacheKey: string) => {
224
+ if (
225
+ cacheKey.startsWith(Constants.CACHE_PREFIX) ||
226
+ cacheKey.indexOf(this.clientId) !== -1
227
+ ) {
228
+ this.removeItem(cacheKey);
229
+ }
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Helper to decrypt all known MSAL keys in localStorage and save them to inMemory storage
235
+ * @returns
236
+ */
237
+ private async importExistingCache(correlationId: string): Promise<void> {
238
+ if (!this.encryptionCookie) {
239
+ return;
240
+ }
241
+
242
+ let accountKeys = getAccountKeys(this);
243
+ accountKeys = await this.importArray(accountKeys, correlationId);
244
+ // Write valid account keys back to map
245
+ this.setItem(StaticCacheKeys.ACCOUNT_KEYS, JSON.stringify(accountKeys));
246
+
247
+ const tokenKeys: TokenKeys = getTokenKeys(this.clientId, this);
248
+ tokenKeys.idToken = await this.importArray(
249
+ tokenKeys.idToken,
250
+ correlationId
251
+ );
252
+ tokenKeys.accessToken = await this.importArray(
253
+ tokenKeys.accessToken,
254
+ correlationId
255
+ );
256
+ tokenKeys.refreshToken = await this.importArray(
257
+ tokenKeys.refreshToken,
258
+ correlationId
259
+ );
260
+ // Write valid token keys back to map
261
+ this.setItem(
262
+ `${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`,
263
+ JSON.stringify(tokenKeys)
264
+ );
265
+ }
266
+
267
+ /**
268
+ * Helper to decrypt and save cache entries
269
+ * @param key
270
+ * @returns
271
+ */
272
+ private async getItemFromEncryptedCache(
273
+ key: string,
274
+ correlationId: string
275
+ ): Promise<string | null> {
276
+ if (!this.encryptionCookie) {
277
+ return null;
278
+ }
279
+
280
+ const rawCache = this.getItem(key);
281
+ if (!rawCache) {
282
+ return null;
283
+ }
284
+
285
+ let encObj: EncryptedData;
286
+ try {
287
+ encObj = JSON.parse(rawCache);
288
+ } catch (e) {
289
+ // Not a valid encrypted object, remove
290
+ return null;
291
+ }
292
+
293
+ if (!encObj.id || !encObj.nonce || !encObj.data) {
294
+ // Data is not encrypted, likely from old version of MSAL. It must be removed because we don't know how old it is.
295
+ this.performanceClient.incrementFields(
296
+ { unencryptedCacheCount: 1 },
297
+ correlationId
298
+ );
299
+ return null;
300
+ }
301
+
302
+ if (encObj.id !== this.encryptionCookie.id) {
303
+ // Data was encrypted with a different key. It must be removed because it is from a previous session.
304
+ this.performanceClient.incrementFields(
305
+ { encryptedCacheExpiredCount: 1 },
306
+ correlationId
307
+ );
308
+ return null;
309
+ }
310
+
311
+ return invokeAsync(
312
+ decrypt,
313
+ PerformanceEvents.Decrypt,
314
+ this.logger,
315
+ this.performanceClient,
316
+ correlationId
317
+ )(
318
+ this.encryptionCookie.key,
319
+ encObj.nonce,
320
+ this.getContext(key),
321
+ encObj.data
322
+ );
323
+ }
324
+
325
+ /**
326
+ * Helper to decrypt and save an array of cache keys
327
+ * @param arr
328
+ * @returns Array of keys successfully imported
329
+ */
330
+ private async importArray(
331
+ arr: Array<string>,
332
+ correlationId: string
333
+ ): Promise<Array<string>> {
334
+ const importedArr: Array<string> = [];
335
+ const promiseArr: Array<Promise<void>> = [];
336
+ arr.forEach((key) => {
337
+ const promise = this.getItemFromEncryptedCache(
338
+ key,
339
+ correlationId
340
+ ).then((value) => {
341
+ if (value) {
342
+ this.memoryStorage.setItem(key, value);
343
+ importedArr.push(key);
344
+ } else {
345
+ // If value is empty, unencrypted or expired remove
346
+ this.removeItem(key);
347
+ }
348
+ });
349
+ promiseArr.push(promise);
350
+ });
351
+
352
+ await Promise.all(promiseArr);
353
+ return importedArr;
354
+ }
355
+
356
+ /**
357
+ * Gets encryption context for a given cache entry. This is clientId for app specific entries, empty string for shared entries
358
+ * @param key
359
+ * @returns
360
+ */
361
+ private getContext(key: string): string {
362
+ let context = "";
363
+ if (key.includes(this.clientId)) {
364
+ context = this.clientId; // Used to bind encryption key to this appId
365
+ }
366
+
367
+ return context;
368
+ }
40
369
  }
@@ -12,14 +12,26 @@ export class MemoryStorage<T> implements IWindowStorage<T> {
12
12
  this.cache = new Map<string, T>();
13
13
  }
14
14
 
15
+ async initialize(): Promise<void> {
16
+ // Memory storage does not require initialization
17
+ }
18
+
15
19
  getItem(key: string): T | null {
16
20
  return this.cache.get(key) || null;
17
21
  }
18
22
 
23
+ getUserData(key: string): T | null {
24
+ return this.getItem(key);
25
+ }
26
+
19
27
  setItem(key: string, value: T): void {
20
28
  this.cache.set(key, value);
21
29
  }
22
30
 
31
+ async setUserData(key: string, value: T): Promise<void> {
32
+ this.setItem(key, value);
33
+ }
34
+
23
35
  removeItem(key: string): void {
24
36
  this.cache.delete(key);
25
37
  }
@@ -18,14 +18,26 @@ export class SessionStorage implements IWindowStorage<string> {
18
18
  }
19
19
  }
20
20
 
21
+ async initialize(): Promise<void> {
22
+ // Session storage does not require initialization
23
+ }
24
+
21
25
  getItem(key: string): string | null {
22
26
  return window.sessionStorage.getItem(key);
23
27
  }
24
28
 
29
+ getUserData(key: string): string | null {
30
+ return this.getItem(key);
31
+ }
32
+
25
33
  setItem(key: string, value: string): void {
26
34
  window.sessionStorage.setItem(key, value);
27
35
  }
28
36
 
37
+ async setUserData(key: string, value: string): Promise<void> {
38
+ this.setItem(key, value);
39
+ }
40
+
29
41
  removeItem(key: string): void {
30
42
  window.sessionStorage.removeItem(key);
31
43
  }