@azure/msal-browser 3.0.1 → 3.1.0

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 (257) hide show
  1. package/README.md +5 -5
  2. package/dist/app/IPublicClientApplication.d.ts +6 -2
  3. package/dist/app/IPublicClientApplication.d.ts.map +1 -1
  4. package/dist/app/IPublicClientApplication.mjs +4 -1
  5. package/dist/app/IPublicClientApplication.mjs.map +1 -1
  6. package/dist/app/PublicClientApplication.d.ts +11 -3
  7. package/dist/app/PublicClientApplication.d.ts.map +1 -1
  8. package/dist/app/PublicClientApplication.mjs +10 -2
  9. package/dist/app/PublicClientApplication.mjs.map +1 -1
  10. package/dist/broker/nativeBroker/NativeMessageHandler.d.ts.map +1 -1
  11. package/dist/broker/nativeBroker/NativeMessageHandler.mjs +5 -4
  12. package/dist/broker/nativeBroker/NativeMessageHandler.mjs.map +1 -1
  13. package/dist/cache/AsyncMemoryStorage.mjs +4 -3
  14. package/dist/cache/AsyncMemoryStorage.mjs.map +1 -1
  15. package/dist/cache/BrowserCacheManager.d.ts +13 -3
  16. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  17. package/dist/cache/BrowserCacheManager.mjs +54 -26
  18. package/dist/cache/BrowserCacheManager.mjs.map +1 -1
  19. package/dist/cache/BrowserStorage.mjs +1 -1
  20. package/dist/cache/BrowserStorage.mjs.map +1 -1
  21. package/dist/cache/CryptoKeyStore.mjs +1 -1
  22. package/dist/cache/CryptoKeyStore.mjs.map +1 -1
  23. package/dist/cache/DatabaseStorage.d.ts.map +1 -1
  24. package/dist/cache/DatabaseStorage.mjs +9 -8
  25. package/dist/cache/DatabaseStorage.mjs.map +1 -1
  26. package/dist/cache/MemoryStorage.mjs +1 -1
  27. package/dist/cache/MemoryStorage.mjs.map +1 -1
  28. package/dist/cache/TokenCache.d.ts.map +1 -1
  29. package/dist/cache/TokenCache.mjs +30 -30
  30. package/dist/cache/TokenCache.mjs.map +1 -1
  31. package/dist/config/Configuration.d.ts +3 -0
  32. package/dist/config/Configuration.d.ts.map +1 -1
  33. package/dist/config/Configuration.mjs +7 -11
  34. package/dist/config/Configuration.mjs.map +1 -1
  35. package/dist/controllers/ControllerFactory.mjs +1 -1
  36. package/dist/controllers/ControllerFactory.mjs.map +1 -1
  37. package/dist/controllers/IController.d.ts +11 -18
  38. package/dist/controllers/IController.d.ts.map +1 -1
  39. package/dist/controllers/StandardController.d.ts +7 -26
  40. package/dist/controllers/StandardController.d.ts.map +1 -1
  41. package/dist/controllers/StandardController.mjs +28 -52
  42. package/dist/controllers/StandardController.mjs.map +1 -1
  43. package/dist/crypto/BrowserCrypto.d.ts.map +1 -1
  44. package/dist/crypto/BrowserCrypto.mjs +4 -3
  45. package/dist/crypto/BrowserCrypto.mjs.map +1 -1
  46. package/dist/crypto/CryptoOps.d.ts +0 -3
  47. package/dist/crypto/CryptoOps.d.ts.map +1 -1
  48. package/dist/crypto/CryptoOps.mjs +14 -17
  49. package/dist/crypto/CryptoOps.mjs.map +1 -1
  50. package/dist/crypto/ModernBrowserCrypto.mjs +1 -1
  51. package/dist/crypto/ModernBrowserCrypto.mjs.map +1 -1
  52. package/dist/crypto/PkceGenerator.d.ts +0 -1
  53. package/dist/crypto/PkceGenerator.d.ts.map +1 -1
  54. package/dist/crypto/PkceGenerator.mjs +8 -8
  55. package/dist/crypto/PkceGenerator.mjs.map +1 -1
  56. package/dist/crypto/SignedHttpRequest.mjs +1 -1
  57. package/dist/crypto/SignedHttpRequest.mjs.map +1 -1
  58. package/dist/encode/Base64Decode.d.ts +6 -19
  59. package/dist/encode/Base64Decode.d.ts.map +1 -1
  60. package/dist/encode/Base64Decode.mjs +17 -70
  61. package/dist/encode/Base64Decode.mjs.map +1 -1
  62. package/dist/encode/Base64Encode.d.ts +15 -27
  63. package/dist/encode/Base64Encode.d.ts.map +1 -1
  64. package/dist/encode/Base64Encode.mjs +36 -75
  65. package/dist/encode/Base64Encode.mjs.map +1 -1
  66. package/dist/error/BrowserAuthError.d.ts +54 -195
  67. package/dist/error/BrowserAuthError.d.ts.map +1 -1
  68. package/dist/error/BrowserAuthError.mjs +150 -381
  69. package/dist/error/BrowserAuthError.mjs.map +1 -1
  70. package/dist/error/BrowserAuthErrorCodes.d.ts +45 -0
  71. package/dist/error/BrowserAuthErrorCodes.d.ts.map +1 -0
  72. package/dist/error/BrowserAuthErrorCodes.mjs +53 -0
  73. package/dist/error/BrowserAuthErrorCodes.mjs.map +1 -0
  74. package/dist/error/BrowserConfigurationAuthError.mjs +1 -1
  75. package/dist/error/BrowserConfigurationAuthError.mjs.map +1 -1
  76. package/dist/error/NativeAuthError.d.ts.map +1 -1
  77. package/dist/error/NativeAuthError.mjs +5 -4
  78. package/dist/error/NativeAuthError.mjs.map +1 -1
  79. package/dist/event/EventHandler.mjs +1 -1
  80. package/dist/event/EventHandler.mjs.map +1 -1
  81. package/dist/event/EventMessage.mjs +1 -1
  82. package/dist/event/EventMessage.mjs.map +1 -1
  83. package/dist/event/EventType.mjs +1 -1
  84. package/dist/event/EventType.mjs.map +1 -1
  85. package/dist/index.d.ts +9 -6
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.mjs +5 -3
  88. package/dist/index.mjs.map +1 -1
  89. package/dist/interaction_client/BaseInteractionClient.d.ts +2 -1
  90. package/dist/interaction_client/BaseInteractionClient.d.ts.map +1 -1
  91. package/dist/interaction_client/BaseInteractionClient.mjs +1 -1
  92. package/dist/interaction_client/BaseInteractionClient.mjs.map +1 -1
  93. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
  94. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs.map +1 -1
  95. package/dist/interaction_client/NativeInteractionClient.d.ts +4 -10
  96. package/dist/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  97. package/dist/interaction_client/NativeInteractionClient.mjs +22 -30
  98. package/dist/interaction_client/NativeInteractionClient.mjs.map +1 -1
  99. package/dist/interaction_client/PopupClient.d.ts.map +1 -1
  100. package/dist/interaction_client/PopupClient.mjs +16 -15
  101. package/dist/interaction_client/PopupClient.mjs.map +1 -1
  102. package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
  103. package/dist/interaction_client/RedirectClient.mjs +7 -6
  104. package/dist/interaction_client/RedirectClient.mjs.map +1 -1
  105. package/dist/interaction_client/SilentAuthCodeClient.d.ts.map +1 -1
  106. package/dist/interaction_client/SilentAuthCodeClient.mjs +5 -4
  107. package/dist/interaction_client/SilentAuthCodeClient.mjs.map +1 -1
  108. package/dist/interaction_client/SilentCacheClient.d.ts +4 -2
  109. package/dist/interaction_client/SilentCacheClient.d.ts.map +1 -1
  110. package/dist/interaction_client/SilentCacheClient.mjs +10 -8
  111. package/dist/interaction_client/SilentCacheClient.mjs.map +1 -1
  112. package/dist/interaction_client/SilentIframeClient.d.ts.map +1 -1
  113. package/dist/interaction_client/SilentIframeClient.mjs +20 -47
  114. package/dist/interaction_client/SilentIframeClient.mjs.map +1 -1
  115. package/dist/interaction_client/SilentRefreshClient.d.ts.map +1 -1
  116. package/dist/interaction_client/SilentRefreshClient.mjs +4 -3
  117. package/dist/interaction_client/SilentRefreshClient.mjs.map +1 -1
  118. package/dist/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  119. package/dist/interaction_client/StandardInteractionClient.mjs +8 -7
  120. package/dist/interaction_client/StandardInteractionClient.mjs.map +1 -1
  121. package/dist/interaction_handler/InteractionHandler.d.ts.map +1 -1
  122. package/dist/interaction_handler/InteractionHandler.mjs +9 -9
  123. package/dist/interaction_handler/InteractionHandler.mjs.map +1 -1
  124. package/dist/interaction_handler/RedirectHandler.d.ts.map +1 -1
  125. package/dist/interaction_handler/RedirectHandler.mjs +11 -10
  126. package/dist/interaction_handler/RedirectHandler.mjs.map +1 -1
  127. package/dist/interaction_handler/SilentHandler.d.ts.map +1 -1
  128. package/dist/interaction_handler/SilentHandler.mjs +10 -9
  129. package/dist/interaction_handler/SilentHandler.mjs.map +1 -1
  130. package/dist/navigation/NavigationClient.mjs +1 -1
  131. package/dist/navigation/NavigationClient.mjs.map +1 -1
  132. package/dist/network/FetchClient.d.ts.map +1 -1
  133. package/dist/network/FetchClient.mjs +9 -8
  134. package/dist/network/FetchClient.mjs.map +1 -1
  135. package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
  136. package/dist/operatingcontext/BaseOperatingContext.mjs.map +1 -1
  137. package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
  138. package/dist/operatingcontext/StandardOperatingContext.mjs.map +1 -1
  139. package/dist/operatingcontext/TeamsAppOperatingContext.mjs +1 -1
  140. package/dist/operatingcontext/TeamsAppOperatingContext.mjs.map +1 -1
  141. package/dist/packageMetadata.d.ts +1 -1
  142. package/dist/packageMetadata.mjs +2 -2
  143. package/dist/packageMetadata.mjs.map +1 -1
  144. package/dist/request/ClearCacheRequest.d.ts +11 -0
  145. package/dist/request/ClearCacheRequest.d.ts.map +1 -0
  146. package/dist/telemetry/BrowserPerformanceClient.d.ts +2 -4
  147. package/dist/telemetry/BrowserPerformanceClient.d.ts.map +1 -1
  148. package/dist/telemetry/BrowserPerformanceClient.mjs +2 -6
  149. package/dist/telemetry/BrowserPerformanceClient.mjs.map +1 -1
  150. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
  151. package/dist/telemetry/BrowserPerformanceMeasurement.mjs.map +1 -1
  152. package/dist/utils/BrowserConstants.mjs +1 -1
  153. package/dist/utils/BrowserConstants.mjs.map +1 -1
  154. package/dist/utils/BrowserProtocolUtils.d.ts.map +1 -1
  155. package/dist/utils/BrowserProtocolUtils.mjs +3 -3
  156. package/dist/utils/BrowserProtocolUtils.mjs.map +1 -1
  157. package/dist/utils/BrowserStringUtils.mjs +1 -1
  158. package/dist/utils/BrowserStringUtils.mjs.map +1 -1
  159. package/dist/utils/BrowserUtils.d.ts +0 -9
  160. package/dist/utils/BrowserUtils.d.ts.map +1 -1
  161. package/dist/utils/BrowserUtils.mjs +8 -33
  162. package/dist/utils/BrowserUtils.mjs.map +1 -1
  163. package/lib/msal-browser.cjs +6601 -7104
  164. package/lib/msal-browser.cjs.map +1 -1
  165. package/lib/msal-browser.js +6601 -7104
  166. package/lib/msal-browser.js.map +1 -1
  167. package/lib/msal-browser.min.js +65 -62
  168. package/package.json +7 -5
  169. package/src/app/IPublicClientApplication.ts +199 -0
  170. package/src/app/PublicClientApplication.ts +405 -0
  171. package/src/broker/nativeBroker/NativeMessageHandler.ts +419 -0
  172. package/src/broker/nativeBroker/NativeRequest.ts +52 -0
  173. package/src/broker/nativeBroker/NativeResponse.ts +56 -0
  174. package/src/cache/AsyncMemoryStorage.ts +158 -0
  175. package/src/cache/BrowserCacheManager.ts +1994 -0
  176. package/src/cache/BrowserStorage.ts +54 -0
  177. package/src/cache/CryptoKeyStore.ts +63 -0
  178. package/src/cache/DatabaseStorage.ts +287 -0
  179. package/src/cache/IAsyncMemoryStorage.ts +36 -0
  180. package/src/cache/ITokenCache.ts +21 -0
  181. package/src/cache/IWindowStorage.ts +36 -0
  182. package/src/cache/MemoryStorage.ts +42 -0
  183. package/src/cache/TokenCache.ts +484 -0
  184. package/src/config/Configuration.ts +375 -0
  185. package/src/controllers/ControllerFactory.ts +55 -0
  186. package/src/controllers/IController.ts +131 -0
  187. package/src/controllers/StandardController.ts +2107 -0
  188. package/src/crypto/BrowserCrypto.ts +135 -0
  189. package/src/crypto/CryptoOps.ts +247 -0
  190. package/src/crypto/ISubtleCrypto.ts +30 -0
  191. package/src/crypto/ModernBrowserCrypto.ts +69 -0
  192. package/src/crypto/PkceGenerator.ts +76 -0
  193. package/src/crypto/SignedHttpRequest.ts +76 -0
  194. package/src/encode/Base64Decode.ts +26 -0
  195. package/src/encode/Base64Encode.ts +52 -0
  196. package/src/error/BrowserAuthError.ts +340 -0
  197. package/src/error/BrowserAuthErrorCodes.ts +56 -0
  198. package/src/error/BrowserConfigurationAuthError.ts +133 -0
  199. package/src/error/NativeAuthError.ts +141 -0
  200. package/src/event/EventHandler.ts +176 -0
  201. package/src/event/EventMessage.ts +125 -0
  202. package/src/event/EventType.ts +33 -0
  203. package/src/index.ts +152 -0
  204. package/src/interaction_client/BaseInteractionClient.ts +301 -0
  205. package/src/interaction_client/HybridSpaAuthorizationCodeClient.ts +16 -0
  206. package/src/interaction_client/NativeInteractionClient.ts +907 -0
  207. package/src/interaction_client/PopupClient.ts +926 -0
  208. package/src/interaction_client/RedirectClient.ts +616 -0
  209. package/src/interaction_client/SilentAuthCodeClient.ts +163 -0
  210. package/src/interaction_client/SilentCacheClient.ts +133 -0
  211. package/src/interaction_client/SilentIframeClient.ts +301 -0
  212. package/src/interaction_client/SilentRefreshClient.ts +120 -0
  213. package/src/interaction_client/StandardInteractionClient.ts +481 -0
  214. package/src/interaction_handler/InteractionHandler.ts +246 -0
  215. package/src/interaction_handler/RedirectHandler.ts +225 -0
  216. package/src/interaction_handler/SilentHandler.ts +266 -0
  217. package/src/navigation/INavigationClient.ts +23 -0
  218. package/src/navigation/NavigationClient.ts +55 -0
  219. package/src/navigation/NavigationOptions.ts +18 -0
  220. package/src/network/FetchClient.ts +130 -0
  221. package/src/operatingcontext/BaseOperatingContext.ts +82 -0
  222. package/src/operatingcontext/StandardOperatingContext.ts +49 -0
  223. package/src/operatingcontext/TeamsAppOperatingContext.ts +48 -0
  224. package/src/packageMetadata.ts +3 -0
  225. package/src/request/AuthorizationCodeRequest.ts +19 -0
  226. package/src/request/AuthorizationUrlRequest.ts +17 -0
  227. package/src/request/ClearCacheRequest.ts +16 -0
  228. package/src/request/EndSessionPopupRequest.ts +26 -0
  229. package/src/request/EndSessionRequest.ts +23 -0
  230. package/src/request/PopupRequest.ts +51 -0
  231. package/src/request/PopupWindowAttributes.ts +22 -0
  232. package/src/request/RedirectRequest.ts +51 -0
  233. package/src/request/SilentRequest.ts +49 -0
  234. package/src/request/SsoSilentRequest.ts +44 -0
  235. package/src/response/AuthenticationResult.ts +13 -0
  236. package/src/telemetry/BrowserPerformanceClient.ts +226 -0
  237. package/src/telemetry/BrowserPerformanceMeasurement.ts +144 -0
  238. package/src/utils/BrowserConstants.ts +241 -0
  239. package/src/utils/BrowserProtocolUtils.ts +57 -0
  240. package/src/utils/BrowserStringUtils.ts +143 -0
  241. package/src/utils/BrowserUtils.ts +156 -0
  242. package/dist/crypto/GuidGenerator.d.ts +0 -13
  243. package/dist/crypto/GuidGenerator.d.ts.map +0 -1
  244. package/dist/crypto/GuidGenerator.mjs +0 -104
  245. package/dist/crypto/GuidGenerator.mjs.map +0 -1
  246. package/dist/internals.d.ts +0 -23
  247. package/dist/internals.d.ts.map +0 -1
  248. package/dist/internals.mjs +0 -28
  249. package/dist/internals.mjs.map +0 -1
  250. package/dist/network/XhrClient.d.ts +0 -41
  251. package/dist/network/XhrClient.d.ts.map +0 -1
  252. package/dist/network/XhrClient.mjs +0 -125
  253. package/dist/network/XhrClient.mjs.map +0 -1
  254. package/dist/utils/MathUtils.d.ts +0 -12
  255. package/dist/utils/MathUtils.d.ts.map +0 -1
  256. package/dist/utils/MathUtils.mjs +0 -26
  257. package/dist/utils/MathUtils.mjs.map +0 -1
@@ -0,0 +1,135 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { BrowserStringUtils } from "../utils/BrowserStringUtils";
7
+ import {
8
+ createBrowserAuthError,
9
+ BrowserAuthErrorCodes,
10
+ } from "../error/BrowserAuthError";
11
+ import { ISubtleCrypto } from "./ISubtleCrypto";
12
+ import { ModernBrowserCrypto } from "./ModernBrowserCrypto";
13
+ import { Logger } from "@azure/msal-common";
14
+ /**
15
+ * See here for more info on RsaHashedKeyGenParams: https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams
16
+ */
17
+ // RSA KeyGen Algorithm
18
+ const PKCS1_V15_KEYGEN_ALG = "RSASSA-PKCS1-v1_5";
19
+ // SHA-256 hashing algorithm
20
+ const S256_HASH_ALG = "SHA-256";
21
+ // MOD length for PoP tokens
22
+ const MODULUS_LENGTH = 2048;
23
+ // Public Exponent
24
+ const PUBLIC_EXPONENT: Uint8Array = new Uint8Array([0x01, 0x00, 0x01]);
25
+
26
+ /**
27
+ * This class implements functions used by the browser library to perform cryptography operations such as
28
+ * hashing and encoding. It also has helper functions to validate the availability of specific APIs.
29
+ */
30
+ export class BrowserCrypto {
31
+ private keygenAlgorithmOptions: RsaHashedKeyGenParams;
32
+ private subtleCrypto: ISubtleCrypto;
33
+ private logger: Logger;
34
+
35
+ constructor(logger: Logger) {
36
+ this.logger = logger;
37
+
38
+ if (this.hasBrowserCrypto()) {
39
+ // Use standard modern web crypto if available
40
+ this.logger.verbose(
41
+ "BrowserCrypto: modern crypto interface available"
42
+ );
43
+ this.subtleCrypto = new ModernBrowserCrypto();
44
+ } else {
45
+ this.logger.error("BrowserCrypto: crypto interface is unavailable");
46
+ throw createBrowserAuthError(
47
+ BrowserAuthErrorCodes.cryptoNonExistent
48
+ );
49
+ }
50
+
51
+ this.keygenAlgorithmOptions = {
52
+ name: PKCS1_V15_KEYGEN_ALG,
53
+ hash: S256_HASH_ALG,
54
+ modulusLength: MODULUS_LENGTH,
55
+ publicExponent: PUBLIC_EXPONENT,
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Check whether browser crypto is available.
61
+ */
62
+ private hasBrowserCrypto(): boolean {
63
+ return "crypto" in window;
64
+ }
65
+
66
+ /**
67
+ * Returns a sha-256 hash of the given dataString as an ArrayBuffer.
68
+ * @param dataString
69
+ */
70
+ async sha256Digest(dataString: string): Promise<ArrayBuffer> {
71
+ const data = BrowserStringUtils.stringToUtf8Arr(dataString);
72
+ // MSR Crypto wants object with name property, instead of string
73
+ return this.subtleCrypto.digest({ name: S256_HASH_ALG }, data);
74
+ }
75
+
76
+ /**
77
+ * Populates buffer with cryptographically random values.
78
+ * @param dataBuffer
79
+ */
80
+ getRandomValues(dataBuffer: Uint8Array): Uint8Array {
81
+ return this.subtleCrypto.getRandomValues(dataBuffer);
82
+ }
83
+
84
+ /**
85
+ * Generates a keypair based on current keygen algorithm config.
86
+ * @param extractable
87
+ * @param usages
88
+ */
89
+ async generateKeyPair(
90
+ extractable: boolean,
91
+ usages: Array<KeyUsage>
92
+ ): Promise<CryptoKeyPair> {
93
+ return this.subtleCrypto.generateKey(
94
+ this.keygenAlgorithmOptions,
95
+ extractable,
96
+ usages
97
+ );
98
+ }
99
+
100
+ /**
101
+ * Export key as Json Web Key (JWK)
102
+ * @param key
103
+ */
104
+ async exportJwk(key: CryptoKey): Promise<JsonWebKey> {
105
+ return this.subtleCrypto.exportKey(key);
106
+ }
107
+
108
+ /**
109
+ * Imports key as Json Web Key (JWK), can set extractable and usages.
110
+ * @param key
111
+ * @param extractable
112
+ * @param usages
113
+ */
114
+ async importJwk(
115
+ key: JsonWebKey,
116
+ extractable: boolean,
117
+ usages: Array<KeyUsage>
118
+ ): Promise<CryptoKey> {
119
+ return this.subtleCrypto.importKey(
120
+ key,
121
+ this.keygenAlgorithmOptions,
122
+ extractable,
123
+ usages
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Signs given data with given key
129
+ * @param key
130
+ * @param data
131
+ */
132
+ async sign(key: CryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
133
+ return this.subtleCrypto.sign(this.keygenAlgorithmOptions, key, data);
134
+ }
135
+ }
@@ -0,0 +1,247 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ ICrypto,
8
+ IPerformanceClient,
9
+ JoseHeader,
10
+ Logger,
11
+ PerformanceEvents,
12
+ PkceCodes,
13
+ SignedHttpRequest,
14
+ SignedHttpRequestParameters,
15
+ } from "@azure/msal-common";
16
+ import { base64Encode, urlEncode, urlEncodeArr } from "../encode/Base64Encode";
17
+ import { base64Decode } from "../encode/Base64Decode";
18
+ import { PkceGenerator } from "./PkceGenerator";
19
+ import { BrowserCrypto } from "./BrowserCrypto";
20
+ import { BrowserStringUtils } from "../utils/BrowserStringUtils";
21
+ import {
22
+ createBrowserAuthError,
23
+ BrowserAuthErrorCodes,
24
+ } from "../error/BrowserAuthError";
25
+ import { CryptoKeyStore } from "../cache/CryptoKeyStore";
26
+
27
+ export type CachedKeyPair = {
28
+ publicKey: CryptoKey;
29
+ privateKey: CryptoKey;
30
+ requestMethod?: string;
31
+ requestUri?: string;
32
+ };
33
+
34
+ /**
35
+ * This class implements MSAL's crypto interface, which allows it to perform base64 encoding and decoding, generating cryptographically random GUIDs and
36
+ * implementing Proof Key for Code Exchange specs for the OAuth Authorization Code Flow using PKCE (rfc here: https://tools.ietf.org/html/rfc7636).
37
+ */
38
+ export class CryptoOps implements ICrypto {
39
+ private browserCrypto: BrowserCrypto;
40
+ private pkceGenerator: PkceGenerator;
41
+ private logger: Logger;
42
+
43
+ /**
44
+ * CryptoOps can be used in contexts outside a PCA instance,
45
+ * meaning there won't be a performance manager available.
46
+ */
47
+ private performanceClient: IPerformanceClient | undefined;
48
+
49
+ private static POP_KEY_USAGES: Array<KeyUsage> = ["sign", "verify"];
50
+ private static EXTRACTABLE: boolean = true;
51
+ private cache: CryptoKeyStore;
52
+
53
+ constructor(logger: Logger, performanceClient?: IPerformanceClient) {
54
+ this.logger = logger;
55
+ // Browser crypto needs to be validated first before any other classes can be set.
56
+ this.browserCrypto = new BrowserCrypto(this.logger);
57
+ this.pkceGenerator = new PkceGenerator(this.browserCrypto);
58
+ this.cache = new CryptoKeyStore(this.logger);
59
+ this.performanceClient = performanceClient;
60
+ }
61
+
62
+ /**
63
+ * Creates a new random GUID - used to populate state and nonce.
64
+ * @returns string (GUID)
65
+ */
66
+ createNewGuid(): string {
67
+ return window.crypto.randomUUID();
68
+ }
69
+
70
+ /**
71
+ * Encodes input string to base64.
72
+ * @param input
73
+ */
74
+ base64Encode(input: string): string {
75
+ return base64Encode(input);
76
+ }
77
+
78
+ /**
79
+ * Decodes input string from base64.
80
+ * @param input
81
+ */
82
+ base64Decode(input: string): string {
83
+ return base64Decode(input);
84
+ }
85
+
86
+ /**
87
+ * Generates PKCE codes used in Authorization Code Flow.
88
+ */
89
+ async generatePkceCodes(): Promise<PkceCodes> {
90
+ return this.pkceGenerator.generateCodes();
91
+ }
92
+
93
+ /**
94
+ * Generates a keypair, stores it and returns a thumbprint
95
+ * @param request
96
+ */
97
+ async getPublicKeyThumbprint(
98
+ request: SignedHttpRequestParameters
99
+ ): Promise<string> {
100
+ const publicKeyThumbMeasurement =
101
+ this.performanceClient?.startMeasurement(
102
+ PerformanceEvents.CryptoOptsGetPublicKeyThumbprint,
103
+ request.correlationId
104
+ );
105
+
106
+ // Generate Keypair
107
+ const keyPair: CryptoKeyPair = await this.browserCrypto.generateKeyPair(
108
+ CryptoOps.EXTRACTABLE,
109
+ CryptoOps.POP_KEY_USAGES
110
+ );
111
+
112
+ // Generate Thumbprint for Public Key
113
+ const publicKeyJwk: JsonWebKey = await this.browserCrypto.exportJwk(
114
+ keyPair.publicKey
115
+ );
116
+
117
+ const pubKeyThumprintObj: JsonWebKey = {
118
+ e: publicKeyJwk.e,
119
+ kty: publicKeyJwk.kty,
120
+ n: publicKeyJwk.n,
121
+ };
122
+
123
+ const publicJwkString: string =
124
+ BrowserStringUtils.getSortedObjectString(pubKeyThumprintObj);
125
+ const publicJwkHash = await this.hashString(publicJwkString);
126
+
127
+ // Generate Thumbprint for Private Key
128
+ const privateKeyJwk: JsonWebKey = await this.browserCrypto.exportJwk(
129
+ keyPair.privateKey
130
+ );
131
+ // Re-import private key to make it unextractable
132
+ const unextractablePrivateKey: CryptoKey =
133
+ await this.browserCrypto.importJwk(privateKeyJwk, false, ["sign"]);
134
+
135
+ // Store Keypair data in keystore
136
+ await this.cache.asymmetricKeys.setItem(publicJwkHash, {
137
+ privateKey: unextractablePrivateKey,
138
+ publicKey: keyPair.publicKey,
139
+ requestMethod: request.resourceRequestMethod,
140
+ requestUri: request.resourceRequestUri,
141
+ });
142
+
143
+ if (publicKeyThumbMeasurement) {
144
+ publicKeyThumbMeasurement.end({
145
+ success: true,
146
+ });
147
+ }
148
+
149
+ return publicJwkHash;
150
+ }
151
+
152
+ /**
153
+ * Removes cryptographic keypair from key store matching the keyId passed in
154
+ * @param kid
155
+ */
156
+ async removeTokenBindingKey(kid: string): Promise<boolean> {
157
+ await this.cache.asymmetricKeys.removeItem(kid);
158
+ const keyFound = await this.cache.asymmetricKeys.containsKey(kid);
159
+ return !keyFound;
160
+ }
161
+
162
+ /**
163
+ * Removes all cryptographic keys from IndexedDB storage
164
+ */
165
+ async clearKeystore(): Promise<boolean> {
166
+ return await this.cache.clear();
167
+ }
168
+
169
+ /**
170
+ * Signs the given object as a jwt payload with private key retrieved by given kid.
171
+ * @param payload
172
+ * @param kid
173
+ */
174
+ async signJwt(
175
+ payload: SignedHttpRequest,
176
+ kid: string,
177
+ correlationId?: string
178
+ ): Promise<string> {
179
+ const signJwtMeasurement = this.performanceClient?.startMeasurement(
180
+ PerformanceEvents.CryptoOptsSignJwt,
181
+ correlationId
182
+ );
183
+ const cachedKeyPair = await this.cache.asymmetricKeys.getItem(kid);
184
+
185
+ if (!cachedKeyPair) {
186
+ throw createBrowserAuthError(
187
+ BrowserAuthErrorCodes.cryptoKeyNotFound
188
+ );
189
+ }
190
+
191
+ // Get public key as JWK
192
+ const publicKeyJwk = await this.browserCrypto.exportJwk(
193
+ cachedKeyPair.publicKey
194
+ );
195
+ const publicKeyJwkString =
196
+ BrowserStringUtils.getSortedObjectString(publicKeyJwk);
197
+
198
+ // Base64URL encode public key thumbprint with keyId only: BASE64URL({ kid: "FULL_PUBLIC_KEY_HASH" })
199
+ const encodedKeyIdThumbprint = urlEncode(JSON.stringify({ kid: kid }));
200
+
201
+ // Generate header
202
+ const shrHeader = JoseHeader.getShrHeaderString({
203
+ kid: encodedKeyIdThumbprint,
204
+ alg: publicKeyJwk.alg,
205
+ });
206
+ const encodedShrHeader = urlEncode(shrHeader);
207
+
208
+ // Generate payload
209
+ payload.cnf = {
210
+ jwk: JSON.parse(publicKeyJwkString),
211
+ };
212
+ const encodedPayload = urlEncode(JSON.stringify(payload));
213
+
214
+ // Form token string
215
+ const tokenString = `${encodedShrHeader}.${encodedPayload}`;
216
+
217
+ // Sign token
218
+ const tokenBuffer = BrowserStringUtils.stringToUtf8Arr(tokenString);
219
+ const signatureBuffer = await this.browserCrypto.sign(
220
+ cachedKeyPair.privateKey,
221
+ tokenBuffer
222
+ );
223
+ const encodedSignature = urlEncodeArr(new Uint8Array(signatureBuffer));
224
+
225
+ const signedJwt = `${tokenString}.${encodedSignature}`;
226
+
227
+ if (signJwtMeasurement) {
228
+ signJwtMeasurement.end({
229
+ success: true,
230
+ });
231
+ }
232
+
233
+ return signedJwt;
234
+ }
235
+
236
+ /**
237
+ * Returns the SHA-256 hash of an input string
238
+ * @param plainText
239
+ */
240
+ async hashString(plainText: string): Promise<string> {
241
+ const hashBuffer: ArrayBuffer = await this.browserCrypto.sha256Digest(
242
+ plainText
243
+ );
244
+ const hashBytes = new Uint8Array(hashBuffer);
245
+ return urlEncodeArr(hashBytes);
246
+ }
247
+ }
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ export interface ISubtleCrypto {
7
+ initPrng?(entropy: Uint8Array): void;
8
+ getRandomValues(dataBuffer: Uint8Array): Uint8Array;
9
+ generateKey(
10
+ algorithm: RsaHashedKeyGenParams,
11
+ extractable: boolean,
12
+ keyUsages: KeyUsage[]
13
+ ): Promise<CryptoKeyPair>;
14
+ exportKey(key: CryptoKey): Promise<JsonWebKey>;
15
+ importKey(
16
+ keyData: JsonWebKey,
17
+ algorithm: RsaHashedImportParams,
18
+ extractable: boolean,
19
+ keyUsages: KeyUsage[]
20
+ ): Promise<CryptoKey>;
21
+ sign(
22
+ algorithm: AlgorithmIdentifier,
23
+ key: CryptoKey,
24
+ data: ArrayBuffer
25
+ ): Promise<ArrayBuffer>;
26
+ digest(
27
+ algorithm: AlgorithmIdentifier,
28
+ data: Uint8Array
29
+ ): Promise<ArrayBuffer>;
30
+ }
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { KEY_FORMAT_JWK } from "../utils/BrowserConstants";
7
+ import { ISubtleCrypto } from "./ISubtleCrypto";
8
+
9
+ export class ModernBrowserCrypto implements ISubtleCrypto {
10
+ getRandomValues(dataBuffer: Uint8Array): Uint8Array {
11
+ return window.crypto.getRandomValues(dataBuffer);
12
+ }
13
+
14
+ async generateKey(
15
+ algorithm: RsaHashedKeyGenParams,
16
+ extractable: boolean,
17
+ keyUsages: KeyUsage[]
18
+ ): Promise<CryptoKeyPair> {
19
+ return window.crypto.subtle.generateKey(
20
+ algorithm,
21
+ extractable,
22
+ keyUsages
23
+ ) as Promise<CryptoKeyPair>;
24
+ }
25
+
26
+ async exportKey(key: CryptoKey): Promise<JsonWebKey> {
27
+ return window.crypto.subtle.exportKey(
28
+ KEY_FORMAT_JWK,
29
+ key
30
+ ) as Promise<JsonWebKey>;
31
+ }
32
+
33
+ async importKey(
34
+ keyData: JsonWebKey,
35
+ algorithm: RsaHashedImportParams,
36
+ extractable: boolean,
37
+ keyUsages: KeyUsage[]
38
+ ): Promise<CryptoKey> {
39
+ return window.crypto.subtle.importKey(
40
+ KEY_FORMAT_JWK,
41
+ keyData,
42
+ algorithm,
43
+ extractable,
44
+ keyUsages
45
+ ) as Promise<CryptoKey>;
46
+ }
47
+
48
+ async sign(
49
+ algorithm: AlgorithmIdentifier,
50
+ key: CryptoKey,
51
+ data: ArrayBuffer
52
+ ): Promise<ArrayBuffer> {
53
+ return window.crypto.subtle.sign(
54
+ algorithm,
55
+ key,
56
+ data
57
+ ) as Promise<ArrayBuffer>;
58
+ }
59
+
60
+ async digest(
61
+ algorithm: AlgorithmIdentifier,
62
+ data: Uint8Array
63
+ ): Promise<ArrayBuffer> {
64
+ return window.crypto.subtle.digest(
65
+ algorithm,
66
+ data
67
+ ) as Promise<ArrayBuffer>;
68
+ }
69
+ }
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { PkceCodes } from "@azure/msal-common";
7
+ import {
8
+ createBrowserAuthError,
9
+ BrowserAuthErrorCodes,
10
+ } from "../error/BrowserAuthError";
11
+ import { urlEncodeArr } from "../encode/Base64Encode";
12
+ import { BrowserCrypto } from "./BrowserCrypto";
13
+
14
+ // Constant byte array length
15
+ const RANDOM_BYTE_ARR_LENGTH = 32;
16
+
17
+ /**
18
+ * Class which exposes APIs to generate PKCE codes and code verifiers.
19
+ */
20
+ export class PkceGenerator {
21
+ private cryptoObj: BrowserCrypto;
22
+
23
+ constructor(cryptoObj: BrowserCrypto) {
24
+ this.cryptoObj = cryptoObj;
25
+ }
26
+
27
+ /**
28
+ * Generates PKCE Codes. See the RFC for more information: https://tools.ietf.org/html/rfc7636
29
+ */
30
+ async generateCodes(): Promise<PkceCodes> {
31
+ const codeVerifier = this.generateCodeVerifier();
32
+ const codeChallenge = await this.generateCodeChallengeFromVerifier(
33
+ codeVerifier
34
+ );
35
+ return {
36
+ verifier: codeVerifier,
37
+ challenge: codeChallenge,
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Generates a random 32 byte buffer and returns the base64
43
+ * encoded string to be used as a PKCE Code Verifier
44
+ */
45
+ private generateCodeVerifier(): string {
46
+ try {
47
+ // Generate random values as utf-8
48
+ const buffer: Uint8Array = new Uint8Array(RANDOM_BYTE_ARR_LENGTH);
49
+ this.cryptoObj.getRandomValues(buffer);
50
+ // encode verifier as base64
51
+ const pkceCodeVerifierB64: string = urlEncodeArr(buffer);
52
+ return pkceCodeVerifierB64;
53
+ } catch (e) {
54
+ throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Creates a base64 encoded PKCE Code Challenge string from the
60
+ * hash created from the PKCE Code Verifier supplied
61
+ */
62
+ private async generateCodeChallengeFromVerifier(
63
+ pkceCodeVerifier: string
64
+ ): Promise<string> {
65
+ try {
66
+ // hashed verifier
67
+ const pkceHashedCodeVerifier = await this.cryptoObj.sha256Digest(
68
+ pkceCodeVerifier
69
+ );
70
+ // encode hash as base64
71
+ return urlEncodeArr(new Uint8Array(pkceHashedCodeVerifier));
72
+ } catch (e) {
73
+ throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { CryptoOps } from "./CryptoOps";
7
+ import {
8
+ Logger,
9
+ LoggerOptions,
10
+ PopTokenGenerator,
11
+ SignedHttpRequestParameters,
12
+ } from "@azure/msal-common";
13
+ import { version, name } from "../packageMetadata";
14
+
15
+ export type SignedHttpRequestOptions = {
16
+ loggerOptions: LoggerOptions;
17
+ };
18
+
19
+ export class SignedHttpRequest {
20
+ private popTokenGenerator: PopTokenGenerator;
21
+ private cryptoOps: CryptoOps;
22
+ private shrParameters: SignedHttpRequestParameters;
23
+ private logger: Logger;
24
+
25
+ constructor(
26
+ shrParameters: SignedHttpRequestParameters,
27
+ shrOptions?: SignedHttpRequestOptions
28
+ ) {
29
+ const loggerOptions = (shrOptions && shrOptions.loggerOptions) || {};
30
+ this.logger = new Logger(loggerOptions, name, version);
31
+ this.cryptoOps = new CryptoOps(this.logger);
32
+ this.popTokenGenerator = new PopTokenGenerator(this.cryptoOps);
33
+ this.shrParameters = shrParameters;
34
+ }
35
+
36
+ /**
37
+ * Generates and caches a keypair for the given request options.
38
+ * @returns Public key digest, which should be sent to the token issuer.
39
+ */
40
+ async generatePublicKeyThumbprint(): Promise<string> {
41
+ const { kid } = await this.popTokenGenerator.generateKid(
42
+ this.shrParameters
43
+ );
44
+
45
+ return kid;
46
+ }
47
+
48
+ /**
49
+ * Generates a signed http request for the given payload with the given key.
50
+ * @param payload Payload to sign (e.g. access token)
51
+ * @param publicKeyThumbprint Public key digest (from generatePublicKeyThumbprint API)
52
+ * @param claims Additional claims to include/override in the signed JWT
53
+ * @returns Pop token signed with the corresponding private key
54
+ */
55
+ async signRequest(
56
+ payload: string,
57
+ publicKeyThumbprint: string,
58
+ claims?: object
59
+ ): Promise<string> {
60
+ return this.popTokenGenerator.signPayload(
61
+ payload,
62
+ publicKeyThumbprint,
63
+ this.shrParameters,
64
+ claims
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Removes cached keys from browser for given public key thumbprint
70
+ * @param publicKeyThumbprint Public key digest (from generatePublicKeyThumbprint API)
71
+ * @returns If keys are properly deleted
72
+ */
73
+ async removeKeys(publicKeyThumbprint: string): Promise<boolean> {
74
+ return await this.cryptoOps.removeTokenBindingKey(publicKeyThumbprint);
75
+ }
76
+ }
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ /**
7
+ * Class which exposes APIs to decode base64 strings to plaintext. See here for implementation details:
8
+ * https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
9
+ */
10
+
11
+ /**
12
+ * Returns a URL-safe plaintext decoded string from b64 encoded input.
13
+ * @param input
14
+ */
15
+ export function base64Decode(input: string): string {
16
+ return new TextDecoder().decode(base64DecToArr(input));
17
+ }
18
+
19
+ /**
20
+ * Decodes base64 into Uint8Array
21
+ * @param base64String
22
+ */
23
+ function base64DecToArr(base64String: string): Uint8Array {
24
+ const binString = atob(base64String);
25
+ return Uint8Array.from(binString, (m) => m.codePointAt(0) || 0);
26
+ }