@azure/msal-common 14.0.0-alpha.1 → 14.0.0-alpha.2

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 (167) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +62 -62
  3. package/dist/account/AccountInfo.d.ts +31 -31
  4. package/dist/account/AuthToken.d.ts +20 -20
  5. package/dist/account/AuthToken.js +48 -48
  6. package/dist/account/CcsCredential.d.ts +8 -8
  7. package/dist/account/CcsCredential.js +9 -9
  8. package/dist/account/ClientCredentials.d.ts +14 -14
  9. package/dist/account/ClientInfo.d.ts +19 -19
  10. package/dist/account/ClientInfo.js +37 -37
  11. package/dist/account/DecodedAuthToken.d.ts +8 -8
  12. package/dist/account/TokenClaims.d.ts +65 -65
  13. package/dist/authority/Authority.d.ts +228 -215
  14. package/dist/authority/Authority.d.ts.map +1 -1
  15. package/dist/authority/Authority.js +716 -682
  16. package/dist/authority/Authority.js.map +1 -1
  17. package/dist/authority/AuthorityFactory.d.ts +30 -30
  18. package/dist/authority/AuthorityFactory.js +47 -47
  19. package/dist/authority/AuthorityMetadata.d.ts +622 -622
  20. package/dist/authority/AuthorityMetadata.js +876 -876
  21. package/dist/authority/AuthorityOptions.d.ts +18 -18
  22. package/dist/authority/AuthorityOptions.js +19 -19
  23. package/dist/authority/AuthorityType.d.ts +9 -9
  24. package/dist/authority/AuthorityType.js +14 -14
  25. package/dist/authority/AzureRegion.d.ts +1 -1
  26. package/dist/authority/AzureRegionConfiguration.d.ts +5 -5
  27. package/dist/authority/CloudDiscoveryMetadata.d.ts +5 -5
  28. package/dist/authority/CloudInstanceDiscoveryErrorResponse.d.ts +13 -13
  29. package/dist/authority/CloudInstanceDiscoveryErrorResponse.js +8 -8
  30. package/dist/authority/CloudInstanceDiscoveryResponse.d.ts +9 -9
  31. package/dist/authority/CloudInstanceDiscoveryResponse.js +8 -8
  32. package/dist/authority/ImdsOptions.d.ts +5 -5
  33. package/dist/authority/OpenIdConfigResponse.d.ts +11 -11
  34. package/dist/authority/OpenIdConfigResponse.js +10 -10
  35. package/dist/authority/ProtocolMode.d.ts +7 -7
  36. package/dist/authority/ProtocolMode.js +12 -12
  37. package/dist/authority/RegionDiscovery.d.ts +30 -30
  38. package/dist/authority/RegionDiscovery.js +108 -108
  39. package/dist/authority/RegionDiscoveryMetadata.d.ts +6 -6
  40. package/dist/broker/nativeBroker/INativeBrokerPlugin.d.ts +15 -15
  41. package/dist/cache/CacheManager.d.ts +443 -443
  42. package/dist/cache/CacheManager.js +1011 -1011
  43. package/dist/cache/entities/AccessTokenEntity.d.ts +56 -56
  44. package/dist/cache/entities/AccessTokenEntity.js +111 -111
  45. package/dist/cache/entities/AccountEntity.d.ts +99 -99
  46. package/dist/cache/entities/AccountEntity.js +248 -248
  47. package/dist/cache/entities/AppMetadataEntity.d.ts +39 -39
  48. package/dist/cache/entities/AppMetadataEntity.js +66 -66
  49. package/dist/cache/entities/AuthorityMetadataEntity.d.ts +47 -47
  50. package/dist/cache/entities/AuthorityMetadataEntity.js +77 -77
  51. package/dist/cache/entities/CacheRecord.d.ts +13 -13
  52. package/dist/cache/entities/CacheRecord.js +13 -13
  53. package/dist/cache/entities/CredentialEntity.d.ts +88 -88
  54. package/dist/cache/entities/CredentialEntity.js +136 -136
  55. package/dist/cache/entities/IdTokenEntity.d.ts +34 -34
  56. package/dist/cache/entities/IdTokenEntity.js +56 -56
  57. package/dist/cache/entities/RefreshTokenEntity.d.ts +36 -36
  58. package/dist/cache/entities/RefreshTokenEntity.js +59 -59
  59. package/dist/cache/entities/ServerTelemetryEntity.d.ts +12 -12
  60. package/dist/cache/entities/ServerTelemetryEntity.js +27 -27
  61. package/dist/cache/entities/ThrottlingEntity.d.ts +13 -13
  62. package/dist/cache/entities/ThrottlingEntity.js +23 -23
  63. package/dist/cache/interface/ICacheManager.d.ts +165 -165
  64. package/dist/cache/interface/ICachePlugin.d.ts +5 -5
  65. package/dist/cache/interface/ISerializableTokenCache.d.ts +4 -4
  66. package/dist/cache/persistence/TokenCacheContext.d.ts +23 -23
  67. package/dist/cache/persistence/TokenCacheContext.js +25 -25
  68. package/dist/cache/utils/CacheTypes.d.ts +62 -62
  69. package/dist/client/AuthorizationCodeClient.d.ts +71 -71
  70. package/dist/client/AuthorizationCodeClient.js +433 -433
  71. package/dist/client/BaseClient.d.ts +50 -50
  72. package/dist/client/BaseClient.js +92 -92
  73. package/dist/client/RefreshTokenClient.d.ts +34 -34
  74. package/dist/client/RefreshTokenClient.js +239 -239
  75. package/dist/client/SilentFlowClient.d.ts +24 -24
  76. package/dist/client/SilentFlowClient.js +94 -94
  77. package/dist/config/AppTokenProvider.d.ts +38 -38
  78. package/dist/config/ClientConfiguration.d.ts +133 -133
  79. package/dist/config/ClientConfiguration.js +88 -88
  80. package/dist/crypto/ICrypto.d.ts +62 -62
  81. package/dist/crypto/ICrypto.js +42 -42
  82. package/dist/crypto/IGuidGenerator.d.ts +4 -4
  83. package/dist/crypto/JoseHeader.d.ts +21 -21
  84. package/dist/crypto/JoseHeader.js +36 -36
  85. package/dist/crypto/PopTokenGenerator.d.ts +57 -57
  86. package/dist/crypto/PopTokenGenerator.js +83 -83
  87. package/dist/crypto/SignedHttpRequest.d.ts +11 -11
  88. package/dist/error/AuthError.d.ts +47 -47
  89. package/dist/error/AuthError.js +51 -51
  90. package/dist/error/ClientAuthError.d.ts +412 -412
  91. package/dist/error/ClientAuthError.js +519 -519
  92. package/dist/error/ClientConfigurationError.d.ts +198 -198
  93. package/dist/error/ClientConfigurationError.js +249 -249
  94. package/dist/error/InteractionRequiredAuthError.d.ts +59 -59
  95. package/dist/error/InteractionRequiredAuthError.js +78 -78
  96. package/dist/error/JoseHeaderError.d.ts +28 -28
  97. package/dist/error/JoseHeaderError.js +39 -39
  98. package/dist/error/ServerError.d.ts +7 -7
  99. package/dist/error/ServerError.js +14 -14
  100. package/dist/index.cjs.js +8843 -8809
  101. package/dist/index.cjs.js.map +1 -1
  102. package/dist/index.d.ts +93 -93
  103. package/dist/index.js +1 -1
  104. package/dist/logger/Logger.d.ts +95 -95
  105. package/dist/logger/Logger.js +197 -197
  106. package/dist/network/INetworkModule.d.ts +29 -29
  107. package/dist/network/INetworkModule.js +14 -14
  108. package/dist/network/NetworkManager.d.ts +32 -32
  109. package/dist/network/NetworkManager.js +33 -33
  110. package/dist/network/RequestThumbprint.d.ts +16 -16
  111. package/dist/network/ThrottlingUtils.d.ts +41 -41
  112. package/dist/network/ThrottlingUtils.js +94 -94
  113. package/dist/packageMetadata.d.ts +2 -2
  114. package/dist/packageMetadata.js +4 -4
  115. package/dist/request/AuthenticationHeaderParser.d.ts +19 -19
  116. package/dist/request/AuthenticationHeaderParser.js +55 -55
  117. package/dist/request/BaseAuthRequest.d.ts +37 -37
  118. package/dist/request/CommonAuthorizationCodeRequest.d.ts +27 -27
  119. package/dist/request/CommonAuthorizationUrlRequest.d.ts +50 -50
  120. package/dist/request/CommonClientCredentialRequest.d.ts +17 -17
  121. package/dist/request/CommonDeviceCodeRequest.d.ts +21 -21
  122. package/dist/request/CommonEndSessionRequest.d.ts +21 -21
  123. package/dist/request/CommonOnBehalfOfRequest.d.ts +13 -13
  124. package/dist/request/CommonRefreshTokenRequest.d.ts +19 -19
  125. package/dist/request/CommonSilentFlowRequest.d.ts +18 -18
  126. package/dist/request/CommonUsernamePasswordRequest.d.ts +17 -17
  127. package/dist/request/NativeRequest.d.ts +19 -19
  128. package/dist/request/NativeSignOutRequest.d.ts +5 -5
  129. package/dist/request/RequestParameterBuilder.d.ts +216 -216
  130. package/dist/request/RequestParameterBuilder.js +374 -374
  131. package/dist/request/RequestValidator.d.ts +33 -33
  132. package/dist/request/RequestValidator.js +83 -83
  133. package/dist/request/ScopeSet.d.ts +88 -88
  134. package/dist/request/ScopeSet.js +197 -197
  135. package/dist/response/AuthenticationResult.d.ts +39 -39
  136. package/dist/response/AuthorizationCodePayload.d.ts +13 -13
  137. package/dist/response/DeviceCodeResponse.d.ts +25 -25
  138. package/dist/response/ExternalTokenResponse.d.ts +15 -15
  139. package/dist/response/IMDSBadResponse.d.ts +4 -4
  140. package/dist/response/ResponseHandler.d.ts +72 -72
  141. package/dist/response/ResponseHandler.js +300 -300
  142. package/dist/response/ServerAuthorizationCodeResponse.d.ts +25 -25
  143. package/dist/response/ServerAuthorizationTokenResponse.d.ts +44 -44
  144. package/dist/telemetry/performance/IPerformanceClient.d.ts +42 -42
  145. package/dist/telemetry/performance/IPerformanceMeasurement.d.ts +5 -5
  146. package/dist/telemetry/performance/PerformanceClient.d.ts +189 -189
  147. package/dist/telemetry/performance/PerformanceClient.js +406 -406
  148. package/dist/telemetry/performance/PerformanceEvent.d.ts +439 -439
  149. package/dist/telemetry/performance/PerformanceEvent.js +227 -227
  150. package/dist/telemetry/performance/StubPerformanceClient.d.ts +19 -19
  151. package/dist/telemetry/performance/StubPerformanceClient.js +36 -36
  152. package/dist/telemetry/server/ServerTelemetryManager.d.ts +65 -65
  153. package/dist/telemetry/server/ServerTelemetryManager.js +196 -196
  154. package/dist/telemetry/server/ServerTelemetryRequest.d.ts +8 -8
  155. package/dist/url/IUri.d.ts +12 -12
  156. package/dist/url/UrlString.d.ts +70 -70
  157. package/dist/url/UrlString.js +242 -242
  158. package/dist/utils/Constants.d.ts +331 -331
  159. package/dist/utils/Constants.js +373 -373
  160. package/dist/utils/MsalTypes.d.ts +6 -6
  161. package/dist/utils/ProtocolUtils.d.ts +42 -42
  162. package/dist/utils/ProtocolUtils.js +71 -71
  163. package/dist/utils/StringUtils.d.ts +53 -53
  164. package/dist/utils/StringUtils.js +124 -124
  165. package/dist/utils/TimeUtils.d.ts +27 -27
  166. package/dist/utils/TimeUtils.js +45 -45
  167. package/package.json +79 -79
@@ -1,4 +1,4 @@
1
- /*! @azure/msal-common v14.0.0-alpha.1 2023-05-08 */
1
+ /*! @azure/msal-common v14.0.0-alpha.2 2023-05-17 */
2
2
  'use strict';
3
3
  import { buildClientInfo } from '../account/ClientInfo.js';
4
4
  import { ClientAuthError } from '../error/ClientAuthError.js';
@@ -20,305 +20,305 @@ import { AppMetadataEntity } from '../cache/entities/AppMetadataEntity.js';
20
20
  import { TokenCacheContext } from '../cache/persistence/TokenCacheContext.js';
21
21
  import { PerformanceEvents } from '../telemetry/performance/PerformanceEvent.js';
22
22
 
23
- /*
24
- * Copyright (c) Microsoft Corporation. All rights reserved.
25
- * Licensed under the MIT License.
26
- */
27
- /**
28
- * Class that handles response parsing.
29
- */
30
- class ResponseHandler {
31
- constructor(clientId, cacheStorage, cryptoObj, logger, serializableCache, persistencePlugin, performanceClient) {
32
- this.clientId = clientId;
33
- this.cacheStorage = cacheStorage;
34
- this.cryptoObj = cryptoObj;
35
- this.logger = logger;
36
- this.serializableCache = serializableCache;
37
- this.persistencePlugin = persistencePlugin;
38
- this.performanceClient = performanceClient;
39
- }
40
- /**
41
- * Function which validates server authorization code response.
42
- * @param serverResponseHash
43
- * @param cachedState
44
- * @param cryptoObj
45
- */
46
- validateServerAuthorizationCodeResponse(serverResponseHash, cachedState, cryptoObj) {
47
- if (!serverResponseHash.state || !cachedState) {
48
- throw !serverResponseHash.state
49
- ? ClientAuthError.createStateNotFoundError("Server State")
50
- : ClientAuthError.createStateNotFoundError("Cached State");
51
- }
52
- if (decodeURIComponent(serverResponseHash.state) !==
53
- decodeURIComponent(cachedState)) {
54
- throw ClientAuthError.createStateMismatchError();
55
- }
56
- // Check for error
57
- if (serverResponseHash.error ||
58
- serverResponseHash.error_description ||
59
- serverResponseHash.suberror) {
60
- if (InteractionRequiredAuthError.isInteractionRequiredError(serverResponseHash.error, serverResponseHash.error_description, serverResponseHash.suberror)) {
61
- throw new InteractionRequiredAuthError(serverResponseHash.error || Constants.EMPTY_STRING, serverResponseHash.error_description, serverResponseHash.suberror, serverResponseHash.timestamp || Constants.EMPTY_STRING, serverResponseHash.trace_id || Constants.EMPTY_STRING, serverResponseHash.correlation_id || Constants.EMPTY_STRING, serverResponseHash.claims || Constants.EMPTY_STRING);
62
- }
63
- throw new ServerError(serverResponseHash.error || Constants.EMPTY_STRING, serverResponseHash.error_description, serverResponseHash.suberror);
64
- }
65
- if (serverResponseHash.client_info) {
66
- buildClientInfo(serverResponseHash.client_info, cryptoObj);
67
- }
68
- }
69
- /**
70
- * Function which validates server authorization token response.
71
- * @param serverResponse
72
- */
73
- validateTokenResponse(serverResponse) {
74
- // Check for error
75
- if (serverResponse.error ||
76
- serverResponse.error_description ||
77
- serverResponse.suberror) {
78
- if (InteractionRequiredAuthError.isInteractionRequiredError(serverResponse.error, serverResponse.error_description, serverResponse.suberror)) {
79
- throw new InteractionRequiredAuthError(serverResponse.error, serverResponse.error_description, serverResponse.suberror, serverResponse.timestamp || Constants.EMPTY_STRING, serverResponse.trace_id || Constants.EMPTY_STRING, serverResponse.correlation_id || Constants.EMPTY_STRING, serverResponse.claims || Constants.EMPTY_STRING);
80
- }
81
- const errString = `${serverResponse.error_codes} - [${serverResponse.timestamp}]: ${serverResponse.error_description} - Correlation ID: ${serverResponse.correlation_id} - Trace ID: ${serverResponse.trace_id}`;
82
- throw new ServerError(serverResponse.error, errString, serverResponse.suberror);
83
- }
84
- }
85
- /**
86
- * Returns a constructed token response based on given string. Also manages the cache updates and cleanups.
87
- * @param serverTokenResponse
88
- * @param authority
89
- */
90
- async handleServerTokenResponse(serverTokenResponse, authority, reqTimestamp, request, authCodePayload, userAssertionHash, handlingRefreshTokenResponse, forceCacheRefreshTokenResponse, serverRequestId) {
91
- this.performanceClient?.addQueueMeasurement(PerformanceEvents.HandleServerTokenResponse, serverTokenResponse.correlation_id);
92
- // create an idToken object (not entity)
93
- let idTokenObj;
94
- if (serverTokenResponse.id_token) {
95
- idTokenObj = new AuthToken(serverTokenResponse.id_token || Constants.EMPTY_STRING, this.cryptoObj);
96
- // token nonce check (TODO: Add a warning if no nonce is given?)
97
- if (authCodePayload &&
98
- !StringUtils.isEmpty(authCodePayload.nonce)) {
99
- if (idTokenObj.claims.nonce !== authCodePayload.nonce) {
100
- throw ClientAuthError.createNonceMismatchError();
101
- }
102
- }
103
- // token max_age check
104
- if (request.maxAge || request.maxAge === 0) {
105
- const authTime = idTokenObj.claims.auth_time;
106
- if (!authTime) {
107
- throw ClientAuthError.createAuthTimeNotFoundError();
108
- }
109
- AuthToken.checkMaxAge(authTime, request.maxAge);
110
- }
111
- }
112
- // generate homeAccountId
113
- this.homeAccountIdentifier = AccountEntity.generateHomeAccountId(serverTokenResponse.client_info || Constants.EMPTY_STRING, authority.authorityType, this.logger, this.cryptoObj, idTokenObj);
114
- // save the response tokens
115
- let requestStateObj;
116
- if (!!authCodePayload && !!authCodePayload.state) {
117
- requestStateObj = ProtocolUtils.parseRequestState(this.cryptoObj, authCodePayload.state);
118
- }
119
- // Add keyId from request to serverTokenResponse if defined
120
- serverTokenResponse.key_id =
121
- serverTokenResponse.key_id || request.sshKid || undefined;
122
- const cacheRecord = this.generateCacheRecord(serverTokenResponse, authority, reqTimestamp, request, idTokenObj, userAssertionHash, authCodePayload);
123
- let cacheContext;
124
- try {
125
- if (this.persistencePlugin && this.serializableCache) {
126
- this.logger.verbose("Persistence enabled, calling beforeCacheAccess");
127
- cacheContext = new TokenCacheContext(this.serializableCache, true);
128
- await this.persistencePlugin.beforeCacheAccess(cacheContext);
129
- }
130
- /*
131
- * When saving a refreshed tokens to the cache, it is expected that the account that was used is present in the cache.
132
- * If not present, we should return null, as it's the case that another application called removeAccount in between
133
- * the calls to getAllAccounts and acquireTokenSilent. We should not overwrite that removal, unless explicitly flagged by
134
- * the developer, as in the case of refresh token flow used in ADAL Node to MSAL Node migration.
135
- */
136
- if (handlingRefreshTokenResponse &&
137
- !forceCacheRefreshTokenResponse &&
138
- cacheRecord.account) {
139
- const key = cacheRecord.account.generateAccountKey();
140
- const account = this.cacheStorage.getAccount(key);
141
- if (!account) {
142
- this.logger.warning("Account used to refresh tokens not in persistence, refreshed tokens will not be stored in the cache");
143
- return ResponseHandler.generateAuthenticationResult(this.cryptoObj, authority, cacheRecord, false, request, idTokenObj, requestStateObj, undefined, serverRequestId);
144
- }
145
- }
146
- await this.cacheStorage.saveCacheRecord(cacheRecord);
147
- }
148
- finally {
149
- if (this.persistencePlugin &&
150
- this.serializableCache &&
151
- cacheContext) {
152
- this.logger.verbose("Persistence enabled, calling afterCacheAccess");
153
- await this.persistencePlugin.afterCacheAccess(cacheContext);
154
- }
155
- }
156
- return ResponseHandler.generateAuthenticationResult(this.cryptoObj, authority, cacheRecord, false, request, idTokenObj, requestStateObj, serverTokenResponse, serverRequestId);
157
- }
158
- /**
159
- * Generates CacheRecord
160
- * @param serverTokenResponse
161
- * @param idTokenObj
162
- * @param authority
163
- */
164
- generateCacheRecord(serverTokenResponse, authority, reqTimestamp, request, idTokenObj, userAssertionHash, authCodePayload) {
165
- const env = authority.getPreferredCache();
166
- if (StringUtils.isEmpty(env)) {
167
- throw ClientAuthError.createInvalidCacheEnvironmentError();
168
- }
169
- // IdToken: non AAD scenarios can have empty realm
170
- let cachedIdToken;
171
- let cachedAccount;
172
- if (!StringUtils.isEmpty(serverTokenResponse.id_token) &&
173
- !!idTokenObj) {
174
- cachedIdToken = IdTokenEntity.createIdTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.id_token || Constants.EMPTY_STRING, this.clientId, idTokenObj.claims.tid || Constants.EMPTY_STRING);
175
- cachedAccount = this.generateAccountEntity(serverTokenResponse, idTokenObj, authority, authCodePayload);
176
- }
177
- // AccessToken
178
- let cachedAccessToken = null;
179
- if (!StringUtils.isEmpty(serverTokenResponse.access_token)) {
180
- // If scopes not returned in server response, use request scopes
181
- const responseScopes = serverTokenResponse.scope
182
- ? ScopeSet.fromString(serverTokenResponse.scope)
183
- : new ScopeSet(request.scopes || []);
184
- /*
185
- * Use timestamp calculated before request
186
- * Server may return timestamps as strings, parse to numbers if so.
187
- */
188
- const expiresIn = (typeof serverTokenResponse.expires_in === "string"
189
- ? parseInt(serverTokenResponse.expires_in, 10)
190
- : serverTokenResponse.expires_in) || 0;
191
- const extExpiresIn = (typeof serverTokenResponse.ext_expires_in === "string"
192
- ? parseInt(serverTokenResponse.ext_expires_in, 10)
193
- : serverTokenResponse.ext_expires_in) || 0;
194
- const refreshIn = (typeof serverTokenResponse.refresh_in === "string"
195
- ? parseInt(serverTokenResponse.refresh_in, 10)
196
- : serverTokenResponse.refresh_in) || undefined;
197
- const tokenExpirationSeconds = reqTimestamp + expiresIn;
198
- const extendedTokenExpirationSeconds = tokenExpirationSeconds + extExpiresIn;
199
- const refreshOnSeconds = refreshIn && refreshIn > 0
200
- ? reqTimestamp + refreshIn
201
- : undefined;
202
- // non AAD scenarios can have empty realm
203
- cachedAccessToken = AccessTokenEntity.createAccessTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.access_token || Constants.EMPTY_STRING, this.clientId, idTokenObj
204
- ? idTokenObj.claims.tid || Constants.EMPTY_STRING
205
- : authority.tenant, responseScopes.printScopes(), tokenExpirationSeconds, extendedTokenExpirationSeconds, this.cryptoObj, refreshOnSeconds, serverTokenResponse.token_type, userAssertionHash, serverTokenResponse.key_id, request.claims, request.requestedClaimsHash);
206
- }
207
- // refreshToken
208
- let cachedRefreshToken = null;
209
- if (!StringUtils.isEmpty(serverTokenResponse.refresh_token)) {
210
- cachedRefreshToken = RefreshTokenEntity.createRefreshTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.refresh_token || Constants.EMPTY_STRING, this.clientId, serverTokenResponse.foci, userAssertionHash);
211
- }
212
- // appMetadata
213
- let cachedAppMetadata = null;
214
- if (!StringUtils.isEmpty(serverTokenResponse.foci)) {
215
- cachedAppMetadata = AppMetadataEntity.createAppMetadataEntity(this.clientId, env, serverTokenResponse.foci);
216
- }
217
- return new CacheRecord(cachedAccount, cachedIdToken, cachedAccessToken, cachedRefreshToken, cachedAppMetadata);
218
- }
219
- /**
220
- * Generate Account
221
- * @param serverTokenResponse
222
- * @param idToken
223
- * @param authority
224
- */
225
- generateAccountEntity(serverTokenResponse, idToken, authority, authCodePayload) {
226
- const authorityType = authority.authorityType;
227
- const cloudGraphHostName = authCodePayload
228
- ? authCodePayload.cloud_graph_host_name
229
- : Constants.EMPTY_STRING;
230
- const msGraphhost = authCodePayload
231
- ? authCodePayload.msgraph_host
232
- : Constants.EMPTY_STRING;
233
- // ADFS does not require client_info in the response
234
- if (authorityType === AuthorityType.Adfs) {
235
- this.logger.verbose("Authority type is ADFS, creating ADFS account");
236
- return AccountEntity.createGenericAccount(this.homeAccountIdentifier, idToken, authority, cloudGraphHostName, msGraphhost);
237
- }
238
- // This fallback applies to B2C as well as they fall under an AAD account type.
239
- if (StringUtils.isEmpty(serverTokenResponse.client_info) &&
240
- authority.protocolMode === "AAD") {
241
- throw ClientAuthError.createClientInfoEmptyError();
242
- }
243
- return serverTokenResponse.client_info
244
- ? AccountEntity.createAccount(serverTokenResponse.client_info, this.homeAccountIdentifier, idToken, authority, cloudGraphHostName, msGraphhost)
245
- : AccountEntity.createGenericAccount(this.homeAccountIdentifier, idToken, authority, cloudGraphHostName, msGraphhost);
246
- }
247
- /**
248
- * Creates an @AuthenticationResult from @CacheRecord , @IdToken , and a boolean that states whether or not the result is from cache.
249
- *
250
- * Optionally takes a state string that is set as-is in the response.
251
- *
252
- * @param cacheRecord
253
- * @param idTokenObj
254
- * @param fromTokenCache
255
- * @param stateString
256
- */
257
- static async generateAuthenticationResult(cryptoObj, authority, cacheRecord, fromTokenCache, request, idTokenObj, requestState, serverTokenResponse, requestId) {
258
- let accessToken = Constants.EMPTY_STRING;
259
- let responseScopes = [];
260
- let expiresOn = null;
261
- let extExpiresOn;
262
- let familyId = Constants.EMPTY_STRING;
263
- if (cacheRecord.accessToken) {
264
- if (cacheRecord.accessToken.tokenType === AuthenticationScheme.POP) {
265
- const popTokenGenerator = new PopTokenGenerator(cryptoObj);
266
- const { secret, keyId } = cacheRecord.accessToken;
267
- if (!keyId) {
268
- throw ClientAuthError.createKeyIdMissingError();
269
- }
270
- accessToken = await popTokenGenerator.signPopToken(secret, keyId, request);
271
- }
272
- else {
273
- accessToken = cacheRecord.accessToken.secret;
274
- }
275
- responseScopes = ScopeSet.fromString(cacheRecord.accessToken.target).asArray();
276
- expiresOn = new Date(Number(cacheRecord.accessToken.expiresOn) * 1000);
277
- extExpiresOn = new Date(Number(cacheRecord.accessToken.extendedExpiresOn) * 1000);
278
- }
279
- if (cacheRecord.appMetadata) {
280
- familyId =
281
- cacheRecord.appMetadata.familyId === THE_FAMILY_ID
282
- ? THE_FAMILY_ID
283
- : Constants.EMPTY_STRING;
284
- }
285
- const uid = idTokenObj?.claims.oid ||
286
- idTokenObj?.claims.sub ||
287
- Constants.EMPTY_STRING;
288
- const tid = idTokenObj?.claims.tid || Constants.EMPTY_STRING;
289
- // for hybrid + native bridge enablement, send back the native account Id
290
- if (serverTokenResponse?.spa_accountid && !!cacheRecord.account) {
291
- cacheRecord.account.nativeAccountId =
292
- serverTokenResponse?.spa_accountid;
293
- }
294
- return {
295
- authority: authority.canonicalAuthority,
296
- uniqueId: uid,
297
- tenantId: tid,
298
- scopes: responseScopes,
299
- account: cacheRecord.account
300
- ? cacheRecord.account.getAccountInfo()
301
- : null,
302
- idToken: idTokenObj ? idTokenObj.rawToken : Constants.EMPTY_STRING,
303
- idTokenClaims: idTokenObj ? idTokenObj.claims : {},
304
- accessToken: accessToken,
305
- fromCache: fromTokenCache,
306
- expiresOn: expiresOn,
307
- correlationId: request.correlationId,
308
- requestId: requestId || Constants.EMPTY_STRING,
309
- extExpiresOn: extExpiresOn,
310
- familyId: familyId,
311
- tokenType: cacheRecord.accessToken?.tokenType || Constants.EMPTY_STRING,
312
- state: requestState
313
- ? requestState.userRequestState
314
- : Constants.EMPTY_STRING,
315
- cloudGraphHostName: cacheRecord.account?.cloudGraphHostName ||
316
- Constants.EMPTY_STRING,
317
- msGraphHost: cacheRecord.account?.msGraphHost || Constants.EMPTY_STRING,
318
- code: serverTokenResponse?.spa_code,
319
- fromNativeBroker: false,
320
- };
321
- }
23
+ /*
24
+ * Copyright (c) Microsoft Corporation. All rights reserved.
25
+ * Licensed under the MIT License.
26
+ */
27
+ /**
28
+ * Class that handles response parsing.
29
+ */
30
+ class ResponseHandler {
31
+ constructor(clientId, cacheStorage, cryptoObj, logger, serializableCache, persistencePlugin, performanceClient) {
32
+ this.clientId = clientId;
33
+ this.cacheStorage = cacheStorage;
34
+ this.cryptoObj = cryptoObj;
35
+ this.logger = logger;
36
+ this.serializableCache = serializableCache;
37
+ this.persistencePlugin = persistencePlugin;
38
+ this.performanceClient = performanceClient;
39
+ }
40
+ /**
41
+ * Function which validates server authorization code response.
42
+ * @param serverResponseHash
43
+ * @param cachedState
44
+ * @param cryptoObj
45
+ */
46
+ validateServerAuthorizationCodeResponse(serverResponseHash, cachedState, cryptoObj) {
47
+ if (!serverResponseHash.state || !cachedState) {
48
+ throw !serverResponseHash.state
49
+ ? ClientAuthError.createStateNotFoundError("Server State")
50
+ : ClientAuthError.createStateNotFoundError("Cached State");
51
+ }
52
+ if (decodeURIComponent(serverResponseHash.state) !==
53
+ decodeURIComponent(cachedState)) {
54
+ throw ClientAuthError.createStateMismatchError();
55
+ }
56
+ // Check for error
57
+ if (serverResponseHash.error ||
58
+ serverResponseHash.error_description ||
59
+ serverResponseHash.suberror) {
60
+ if (InteractionRequiredAuthError.isInteractionRequiredError(serverResponseHash.error, serverResponseHash.error_description, serverResponseHash.suberror)) {
61
+ throw new InteractionRequiredAuthError(serverResponseHash.error || Constants.EMPTY_STRING, serverResponseHash.error_description, serverResponseHash.suberror, serverResponseHash.timestamp || Constants.EMPTY_STRING, serverResponseHash.trace_id || Constants.EMPTY_STRING, serverResponseHash.correlation_id || Constants.EMPTY_STRING, serverResponseHash.claims || Constants.EMPTY_STRING);
62
+ }
63
+ throw new ServerError(serverResponseHash.error || Constants.EMPTY_STRING, serverResponseHash.error_description, serverResponseHash.suberror);
64
+ }
65
+ if (serverResponseHash.client_info) {
66
+ buildClientInfo(serverResponseHash.client_info, cryptoObj);
67
+ }
68
+ }
69
+ /**
70
+ * Function which validates server authorization token response.
71
+ * @param serverResponse
72
+ */
73
+ validateTokenResponse(serverResponse) {
74
+ // Check for error
75
+ if (serverResponse.error ||
76
+ serverResponse.error_description ||
77
+ serverResponse.suberror) {
78
+ if (InteractionRequiredAuthError.isInteractionRequiredError(serverResponse.error, serverResponse.error_description, serverResponse.suberror)) {
79
+ throw new InteractionRequiredAuthError(serverResponse.error, serverResponse.error_description, serverResponse.suberror, serverResponse.timestamp || Constants.EMPTY_STRING, serverResponse.trace_id || Constants.EMPTY_STRING, serverResponse.correlation_id || Constants.EMPTY_STRING, serverResponse.claims || Constants.EMPTY_STRING);
80
+ }
81
+ const errString = `${serverResponse.error_codes} - [${serverResponse.timestamp}]: ${serverResponse.error_description} - Correlation ID: ${serverResponse.correlation_id} - Trace ID: ${serverResponse.trace_id}`;
82
+ throw new ServerError(serverResponse.error, errString, serverResponse.suberror);
83
+ }
84
+ }
85
+ /**
86
+ * Returns a constructed token response based on given string. Also manages the cache updates and cleanups.
87
+ * @param serverTokenResponse
88
+ * @param authority
89
+ */
90
+ async handleServerTokenResponse(serverTokenResponse, authority, reqTimestamp, request, authCodePayload, userAssertionHash, handlingRefreshTokenResponse, forceCacheRefreshTokenResponse, serverRequestId) {
91
+ this.performanceClient?.addQueueMeasurement(PerformanceEvents.HandleServerTokenResponse, serverTokenResponse.correlation_id);
92
+ // create an idToken object (not entity)
93
+ let idTokenObj;
94
+ if (serverTokenResponse.id_token) {
95
+ idTokenObj = new AuthToken(serverTokenResponse.id_token || Constants.EMPTY_STRING, this.cryptoObj);
96
+ // token nonce check (TODO: Add a warning if no nonce is given?)
97
+ if (authCodePayload &&
98
+ !StringUtils.isEmpty(authCodePayload.nonce)) {
99
+ if (idTokenObj.claims.nonce !== authCodePayload.nonce) {
100
+ throw ClientAuthError.createNonceMismatchError();
101
+ }
102
+ }
103
+ // token max_age check
104
+ if (request.maxAge || request.maxAge === 0) {
105
+ const authTime = idTokenObj.claims.auth_time;
106
+ if (!authTime) {
107
+ throw ClientAuthError.createAuthTimeNotFoundError();
108
+ }
109
+ AuthToken.checkMaxAge(authTime, request.maxAge);
110
+ }
111
+ }
112
+ // generate homeAccountId
113
+ this.homeAccountIdentifier = AccountEntity.generateHomeAccountId(serverTokenResponse.client_info || Constants.EMPTY_STRING, authority.authorityType, this.logger, this.cryptoObj, idTokenObj);
114
+ // save the response tokens
115
+ let requestStateObj;
116
+ if (!!authCodePayload && !!authCodePayload.state) {
117
+ requestStateObj = ProtocolUtils.parseRequestState(this.cryptoObj, authCodePayload.state);
118
+ }
119
+ // Add keyId from request to serverTokenResponse if defined
120
+ serverTokenResponse.key_id =
121
+ serverTokenResponse.key_id || request.sshKid || undefined;
122
+ const cacheRecord = this.generateCacheRecord(serverTokenResponse, authority, reqTimestamp, request, idTokenObj, userAssertionHash, authCodePayload);
123
+ let cacheContext;
124
+ try {
125
+ if (this.persistencePlugin && this.serializableCache) {
126
+ this.logger.verbose("Persistence enabled, calling beforeCacheAccess");
127
+ cacheContext = new TokenCacheContext(this.serializableCache, true);
128
+ await this.persistencePlugin.beforeCacheAccess(cacheContext);
129
+ }
130
+ /*
131
+ * When saving a refreshed tokens to the cache, it is expected that the account that was used is present in the cache.
132
+ * If not present, we should return null, as it's the case that another application called removeAccount in between
133
+ * the calls to getAllAccounts and acquireTokenSilent. We should not overwrite that removal, unless explicitly flagged by
134
+ * the developer, as in the case of refresh token flow used in ADAL Node to MSAL Node migration.
135
+ */
136
+ if (handlingRefreshTokenResponse &&
137
+ !forceCacheRefreshTokenResponse &&
138
+ cacheRecord.account) {
139
+ const key = cacheRecord.account.generateAccountKey();
140
+ const account = this.cacheStorage.getAccount(key);
141
+ if (!account) {
142
+ this.logger.warning("Account used to refresh tokens not in persistence, refreshed tokens will not be stored in the cache");
143
+ return ResponseHandler.generateAuthenticationResult(this.cryptoObj, authority, cacheRecord, false, request, idTokenObj, requestStateObj, undefined, serverRequestId);
144
+ }
145
+ }
146
+ await this.cacheStorage.saveCacheRecord(cacheRecord);
147
+ }
148
+ finally {
149
+ if (this.persistencePlugin &&
150
+ this.serializableCache &&
151
+ cacheContext) {
152
+ this.logger.verbose("Persistence enabled, calling afterCacheAccess");
153
+ await this.persistencePlugin.afterCacheAccess(cacheContext);
154
+ }
155
+ }
156
+ return ResponseHandler.generateAuthenticationResult(this.cryptoObj, authority, cacheRecord, false, request, idTokenObj, requestStateObj, serverTokenResponse, serverRequestId);
157
+ }
158
+ /**
159
+ * Generates CacheRecord
160
+ * @param serverTokenResponse
161
+ * @param idTokenObj
162
+ * @param authority
163
+ */
164
+ generateCacheRecord(serverTokenResponse, authority, reqTimestamp, request, idTokenObj, userAssertionHash, authCodePayload) {
165
+ const env = authority.getPreferredCache();
166
+ if (StringUtils.isEmpty(env)) {
167
+ throw ClientAuthError.createInvalidCacheEnvironmentError();
168
+ }
169
+ // IdToken: non AAD scenarios can have empty realm
170
+ let cachedIdToken;
171
+ let cachedAccount;
172
+ if (!StringUtils.isEmpty(serverTokenResponse.id_token) &&
173
+ !!idTokenObj) {
174
+ cachedIdToken = IdTokenEntity.createIdTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.id_token || Constants.EMPTY_STRING, this.clientId, idTokenObj.claims.tid || Constants.EMPTY_STRING);
175
+ cachedAccount = this.generateAccountEntity(serverTokenResponse, idTokenObj, authority, authCodePayload);
176
+ }
177
+ // AccessToken
178
+ let cachedAccessToken = null;
179
+ if (!StringUtils.isEmpty(serverTokenResponse.access_token)) {
180
+ // If scopes not returned in server response, use request scopes
181
+ const responseScopes = serverTokenResponse.scope
182
+ ? ScopeSet.fromString(serverTokenResponse.scope)
183
+ : new ScopeSet(request.scopes || []);
184
+ /*
185
+ * Use timestamp calculated before request
186
+ * Server may return timestamps as strings, parse to numbers if so.
187
+ */
188
+ const expiresIn = (typeof serverTokenResponse.expires_in === "string"
189
+ ? parseInt(serverTokenResponse.expires_in, 10)
190
+ : serverTokenResponse.expires_in) || 0;
191
+ const extExpiresIn = (typeof serverTokenResponse.ext_expires_in === "string"
192
+ ? parseInt(serverTokenResponse.ext_expires_in, 10)
193
+ : serverTokenResponse.ext_expires_in) || 0;
194
+ const refreshIn = (typeof serverTokenResponse.refresh_in === "string"
195
+ ? parseInt(serverTokenResponse.refresh_in, 10)
196
+ : serverTokenResponse.refresh_in) || undefined;
197
+ const tokenExpirationSeconds = reqTimestamp + expiresIn;
198
+ const extendedTokenExpirationSeconds = tokenExpirationSeconds + extExpiresIn;
199
+ const refreshOnSeconds = refreshIn && refreshIn > 0
200
+ ? reqTimestamp + refreshIn
201
+ : undefined;
202
+ // non AAD scenarios can have empty realm
203
+ cachedAccessToken = AccessTokenEntity.createAccessTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.access_token || Constants.EMPTY_STRING, this.clientId, idTokenObj
204
+ ? idTokenObj.claims.tid || Constants.EMPTY_STRING
205
+ : authority.tenant, responseScopes.printScopes(), tokenExpirationSeconds, extendedTokenExpirationSeconds, this.cryptoObj, refreshOnSeconds, serverTokenResponse.token_type, userAssertionHash, serverTokenResponse.key_id, request.claims, request.requestedClaimsHash);
206
+ }
207
+ // refreshToken
208
+ let cachedRefreshToken = null;
209
+ if (!StringUtils.isEmpty(serverTokenResponse.refresh_token)) {
210
+ cachedRefreshToken = RefreshTokenEntity.createRefreshTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.refresh_token || Constants.EMPTY_STRING, this.clientId, serverTokenResponse.foci, userAssertionHash);
211
+ }
212
+ // appMetadata
213
+ let cachedAppMetadata = null;
214
+ if (!StringUtils.isEmpty(serverTokenResponse.foci)) {
215
+ cachedAppMetadata = AppMetadataEntity.createAppMetadataEntity(this.clientId, env, serverTokenResponse.foci);
216
+ }
217
+ return new CacheRecord(cachedAccount, cachedIdToken, cachedAccessToken, cachedRefreshToken, cachedAppMetadata);
218
+ }
219
+ /**
220
+ * Generate Account
221
+ * @param serverTokenResponse
222
+ * @param idToken
223
+ * @param authority
224
+ */
225
+ generateAccountEntity(serverTokenResponse, idToken, authority, authCodePayload) {
226
+ const authorityType = authority.authorityType;
227
+ const cloudGraphHostName = authCodePayload
228
+ ? authCodePayload.cloud_graph_host_name
229
+ : Constants.EMPTY_STRING;
230
+ const msGraphhost = authCodePayload
231
+ ? authCodePayload.msgraph_host
232
+ : Constants.EMPTY_STRING;
233
+ // ADFS does not require client_info in the response
234
+ if (authorityType === AuthorityType.Adfs) {
235
+ this.logger.verbose("Authority type is ADFS, creating ADFS account");
236
+ return AccountEntity.createGenericAccount(this.homeAccountIdentifier, idToken, authority, cloudGraphHostName, msGraphhost);
237
+ }
238
+ // This fallback applies to B2C as well as they fall under an AAD account type.
239
+ if (StringUtils.isEmpty(serverTokenResponse.client_info) &&
240
+ authority.protocolMode === "AAD") {
241
+ throw ClientAuthError.createClientInfoEmptyError();
242
+ }
243
+ return serverTokenResponse.client_info
244
+ ? AccountEntity.createAccount(serverTokenResponse.client_info, this.homeAccountIdentifier, idToken, authority, cloudGraphHostName, msGraphhost)
245
+ : AccountEntity.createGenericAccount(this.homeAccountIdentifier, idToken, authority, cloudGraphHostName, msGraphhost);
246
+ }
247
+ /**
248
+ * Creates an @AuthenticationResult from @CacheRecord , @IdToken , and a boolean that states whether or not the result is from cache.
249
+ *
250
+ * Optionally takes a state string that is set as-is in the response.
251
+ *
252
+ * @param cacheRecord
253
+ * @param idTokenObj
254
+ * @param fromTokenCache
255
+ * @param stateString
256
+ */
257
+ static async generateAuthenticationResult(cryptoObj, authority, cacheRecord, fromTokenCache, request, idTokenObj, requestState, serverTokenResponse, requestId) {
258
+ let accessToken = Constants.EMPTY_STRING;
259
+ let responseScopes = [];
260
+ let expiresOn = null;
261
+ let extExpiresOn;
262
+ let familyId = Constants.EMPTY_STRING;
263
+ if (cacheRecord.accessToken) {
264
+ if (cacheRecord.accessToken.tokenType === AuthenticationScheme.POP) {
265
+ const popTokenGenerator = new PopTokenGenerator(cryptoObj);
266
+ const { secret, keyId } = cacheRecord.accessToken;
267
+ if (!keyId) {
268
+ throw ClientAuthError.createKeyIdMissingError();
269
+ }
270
+ accessToken = await popTokenGenerator.signPopToken(secret, keyId, request);
271
+ }
272
+ else {
273
+ accessToken = cacheRecord.accessToken.secret;
274
+ }
275
+ responseScopes = ScopeSet.fromString(cacheRecord.accessToken.target).asArray();
276
+ expiresOn = new Date(Number(cacheRecord.accessToken.expiresOn) * 1000);
277
+ extExpiresOn = new Date(Number(cacheRecord.accessToken.extendedExpiresOn) * 1000);
278
+ }
279
+ if (cacheRecord.appMetadata) {
280
+ familyId =
281
+ cacheRecord.appMetadata.familyId === THE_FAMILY_ID
282
+ ? THE_FAMILY_ID
283
+ : Constants.EMPTY_STRING;
284
+ }
285
+ const uid = idTokenObj?.claims.oid ||
286
+ idTokenObj?.claims.sub ||
287
+ Constants.EMPTY_STRING;
288
+ const tid = idTokenObj?.claims.tid || Constants.EMPTY_STRING;
289
+ // for hybrid + native bridge enablement, send back the native account Id
290
+ if (serverTokenResponse?.spa_accountid && !!cacheRecord.account) {
291
+ cacheRecord.account.nativeAccountId =
292
+ serverTokenResponse?.spa_accountid;
293
+ }
294
+ return {
295
+ authority: authority.canonicalAuthority,
296
+ uniqueId: uid,
297
+ tenantId: tid,
298
+ scopes: responseScopes,
299
+ account: cacheRecord.account
300
+ ? cacheRecord.account.getAccountInfo()
301
+ : null,
302
+ idToken: idTokenObj ? idTokenObj.rawToken : Constants.EMPTY_STRING,
303
+ idTokenClaims: idTokenObj ? idTokenObj.claims : {},
304
+ accessToken: accessToken,
305
+ fromCache: fromTokenCache,
306
+ expiresOn: expiresOn,
307
+ correlationId: request.correlationId,
308
+ requestId: requestId || Constants.EMPTY_STRING,
309
+ extExpiresOn: extExpiresOn,
310
+ familyId: familyId,
311
+ tokenType: cacheRecord.accessToken?.tokenType || Constants.EMPTY_STRING,
312
+ state: requestState
313
+ ? requestState.userRequestState
314
+ : Constants.EMPTY_STRING,
315
+ cloudGraphHostName: cacheRecord.account?.cloudGraphHostName ||
316
+ Constants.EMPTY_STRING,
317
+ msGraphHost: cacheRecord.account?.msGraphHost || Constants.EMPTY_STRING,
318
+ code: serverTokenResponse?.spa_code,
319
+ fromNativeBroker: false,
320
+ };
321
+ }
322
322
  }
323
323
 
324
324
  export { ResponseHandler };