Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Track ApiId when setting/getting accounts",
"packageName": "@azure/msal-browser",
"email": "thomas.norling@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Track APIId when setting/getting accounts",
"packageName": "@azure/msal-common",
"email": "thomas.norling@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Track ApiId when setting/getting accounts",
"packageName": "@azure/msal-node",
"email": "thomas.norling@microsoft.com",
"dependentChangeType": "patch"
}
18 changes: 16 additions & 2 deletions lib/msal-browser/src/cache/BrowserCacheManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import {
createBrowserAuthError,
} from "../error/BrowserAuthError.js";
import {
ApiId,
apiIdToName,
BrowserCacheLocation,
InMemoryCacheKeys,
INTERACTION_TYPE,
Expand Down Expand Up @@ -1045,6 +1047,13 @@ export class BrowserCacheManager extends CacheManager {
return null;
}

this.performanceClient.addFields(
{
accountCachedBy: apiIdToName(parsedAccount.cachedByApiId),
},
correlationId
);

return CacheManager.toObject<AccountEntity>(
new AccountEntity(),
parsedAccount
Expand All @@ -1058,14 +1067,16 @@ export class BrowserCacheManager extends CacheManager {
async setAccount(
account: AccountEntity,
correlationId: string,
kmsi: boolean
kmsi: boolean,
apiId: number
): Promise<void> {
this.logger.trace("BrowserCacheManager.setAccount called");
const key = this.generateAccountKey(
AccountEntity.getAccountInfo(account)
);
const timestamp = Date.now().toString();
account.lastUpdatedAt = timestamp;
account.cachedByApiId = apiId;
await this.setUserData(
key,
JSON.stringify(account),
Expand Down Expand Up @@ -2279,7 +2290,8 @@ export class BrowserCacheManager extends CacheManager {
result.correlationId,
AuthToken.isKmsi(
AuthToken.extractTokenClaims(result.idToken, base64Decode)
)
),
ApiId.hydrateCache
);
}

Expand All @@ -2293,13 +2305,15 @@ export class BrowserCacheManager extends CacheManager {
cacheRecord: CacheRecord,
correlationId: string,
kmsi: boolean,
apiId: ApiId,
storeInCache?: StoreInCache
): Promise<void> {
try {
await super.saveCacheRecord(
cacheRecord,
correlationId,
kmsi,
apiId,
storeInCache
);
} catch (e) {
Expand Down
7 changes: 5 additions & 2 deletions lib/msal-browser/src/cache/TokenCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
import type { AuthenticationResult } from "../response/AuthenticationResult.js";
import { base64Decode } from "../encode/Base64Decode.js";
import * as BrowserCrypto from "../crypto/BrowserCrypto.js";
import { ApiId } from "../utils/BrowserConstants.js";

export type LoadTokenOptions = {
clientInfo?: string;
Expand Down Expand Up @@ -191,7 +192,8 @@ export class TokenCache implements ITokenCache {
await this.storage.setAccount(
accountEntity,
correlationId,
AuthToken.isKmsi(idTokenClaims || {})
AuthToken.isKmsi(idTokenClaims || {}),
ApiId.loadExternalTokens
);
return accountEntity;
} else if (!authority || (!clientInfo && !idTokenClaims)) {
Expand Down Expand Up @@ -231,7 +233,8 @@ export class TokenCache implements ITokenCache {
await this.storage.setAccount(
cachedAccount,
correlationId,
AuthToken.isKmsi(idTokenClaims || {})
AuthToken.isKmsi(idTokenClaims || {}),
ApiId.loadExternalTokens
);
return cachedAccount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,8 @@ export class NestedAppAuthController implements IController {
await this.browserStorage.setAccount(
accountEntity,
result.correlationId,
AuthToken.isKmsi(result.idTokenClaims)
AuthToken.isKmsi(result.idTokenClaims),
ApiId.hydrateCache
);
return this.browserStorage.hydrateCache(result, request);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/msal-browser/src/controllers/StandardController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1627,7 +1627,8 @@ export class StandardController implements IController {
await this.browserStorage.setAccount(
accountEntity,
result.correlationId,
AuthToken.isKmsi(result.idTokenClaims)
AuthToken.isKmsi(result.idTokenClaims),
ApiId.hydrateCache
);

if (result.fromNativeBroker) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ export abstract class CustomAuthInteractionClientBase extends StandardInteractio
protected async handleTokenResponse(
tokenResponse: SignInTokenResponse,
requestScopes: string[],
correlationId: string
correlationId: string,
apiId: number
): Promise<AuthenticationResult> {
this.logger.verbose("Processing token response.", correlationId);

Expand All @@ -114,7 +115,8 @@ export abstract class CustomAuthInteractionClientBase extends StandardInteractio
correlationId:
tokenResponse.correlation_id ?? correlationId,
scopes: requestScopes,
}
},
apiId
);

return result as AuthenticationResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ export class JitClient extends CustomAuthInteractionClientBase {
const authResult = await this.handleTokenResponse(
tokenResponse,
scopes,
tokenResponse.correlation_id || continueResponse.correlation_id
tokenResponse.correlation_id || continueResponse.correlation_id,
apiId
);

return createJitCompletedResult({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ export class MfaClient extends CustomAuthInteractionClientBase {
const result = await this.handleTokenResponse(
tokenResponse,
scopes,
tokenResponse.correlation_id ?? parameters.correlationId
tokenResponse.correlation_id ?? parameters.correlationId,
apiId
);

return createMfaCompletedResult({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ export class CustomAuthSilentCacheClient extends CustomAuthInteractionClientBase

const refreshTokenResult =
await refreshTokenClient.acquireTokenByRefreshToken(
silentRequest
silentRequest,
PublicApiId.ACCOUNT_GET_ACCESS_TOKEN
);

this.logger.verbose(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ export class SignInClient extends CustomAuthInteractionClientBase {
),
scopes,
parameters.correlationId,
telemetryManager
telemetryManager,
apiId
);
}

Expand Down Expand Up @@ -220,7 +221,8 @@ export class SignInClient extends CustomAuthInteractionClientBase {
),
scopes,
parameters.correlationId,
telemetryManager
telemetryManager,
apiId
);
}

Expand Down Expand Up @@ -263,7 +265,8 @@ export class SignInClient extends CustomAuthInteractionClientBase {
),
scopes,
parameters.correlationId,
telemetryManager
telemetryManager,
apiId
);
}

Expand All @@ -279,7 +282,8 @@ export class SignInClient extends CustomAuthInteractionClientBase {
tokenEndpointCaller: () => Promise<SignInTokenResponse>,
scopes: string[],
correlationId: string,
telemetryManager: ServerTelemetryManager
telemetryManager: ServerTelemetryManager,
apiId: number
): Promise<
| SignInCompletedResult
| SignInJitRequiredResult
Expand All @@ -301,7 +305,8 @@ export class SignInClient extends CustomAuthInteractionClientBase {
const authResult = await this.handleTokenResponse(
tokenResponse,
scopes,
correlationId
correlationId,
apiId
);

return createSignInCompleteResult({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,8 @@ export class PlatformAuthInteractionClient extends BaseInteractionClient {
await this.browserStorage.setAccount(
accountEntity,
this.correlationId,
kmsi
kmsi,
this.apiId
);
// Remove any existing cached tokens for this account in browser storage
this.browserStorage.removeAccountContext(
Expand Down Expand Up @@ -817,6 +818,7 @@ export class PlatformAuthInteractionClient extends BaseInteractionClient {
nativeCacheRecord,
this.correlationId,
AuthToken.isKmsi(idTokenClaims),
this.apiId,
request.storeInCache
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export class SilentAuthCodeClient extends StandardInteractionClient {
cloud_instance_host_name: request.cloudInstanceHostName,
},
silentRequest,
this.apiId,
false
);
} catch (e) {
Expand Down
12 changes: 7 additions & 5 deletions lib/msal-browser/src/interaction_client/SilentRefreshClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ export class SilentRefreshClient extends StandardInteractionClient {
this.logger,
this.performanceClient,
request.correlationId
)(silentRequest).catch((e: AuthError) => {
(e as AuthError).setCorrelationId(this.correlationId);
serverTelemetryManager.cacheFailedRequest(e);
throw e;
}) as Promise<AuthenticationResult>;
)(silentRequest, ApiId.acquireTokenSilent_silentFlow).catch(
(e: AuthError) => {
(e as AuthError).setCorrelationId(this.correlationId);
serverTelemetryManager.cacheFailedRequest(e);
throw e;
}
) as Promise<AuthenticationResult>;
}

/**
Expand Down
13 changes: 10 additions & 3 deletions lib/msal-browser/src/interaction_handler/InteractionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
BrowserAuthErrorCodes,
} from "../error/BrowserAuthError.js";
import { AuthenticationResult } from "../response/AuthenticationResult.js";
import { ApiId } from "../utils/BrowserConstants.js";

/**
* Abstract class which defines operations for a browser interaction handling class.
Expand Down Expand Up @@ -56,7 +57,8 @@ export class InteractionHandler {
*/
async handleCodeResponse(
response: AuthorizeResponse,
request: CommonAuthorizationUrlRequest
request: CommonAuthorizationUrlRequest,
apiId: ApiId
): Promise<AuthenticationResult> {
this.performanceClient.addQueueMeasurement(
PerformanceEvents.HandleCodeResponse,
Expand Down Expand Up @@ -89,7 +91,7 @@ export class InteractionHandler {
this.logger,
this.performanceClient,
request.correlationId
)(authCodeResponse, request);
)(authCodeResponse, request, apiId);
}

/**
Expand All @@ -103,6 +105,7 @@ export class InteractionHandler {
async handleCodeResponseFromServer(
authCodeResponse: AuthorizationCodePayload,
request: CommonAuthorizationUrlRequest,
apiId: ApiId,
validateNonce: boolean = true
): Promise<AuthenticationResult> {
this.performanceClient.addQueueMeasurement(
Expand Down Expand Up @@ -152,7 +155,11 @@ export class InteractionHandler {
this.logger,
this.performanceClient,
request.correlationId
)(this.authCodeRequest, authCodeResponse)) as AuthenticationResult;
)(
this.authCodeRequest,
apiId,
authCodeResponse
)) as AuthenticationResult;
return tokenResponse;
}

Expand Down
3 changes: 2 additions & 1 deletion lib/msal-browser/src/protocol/Authorize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ export async function handleResponseCode(
logger,
performanceClient,
request.correlationId
)(response, request);
)(response, request, apiId);

return result;
}
Expand Down Expand Up @@ -556,6 +556,7 @@ export async function handleResponseEAR(
authority,
TimeUtils.nowSeconds(),
request,
apiId,
additionalData,
undefined,
undefined,
Expand Down
28 changes: 27 additions & 1 deletion lib/msal-browser/src/utils/BrowserConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ export type InMemoryCacheKeys =

/**
* API Codes for Telemetry purposes.
* Before adding a new code you must claim it in the MSAL Telemetry tracker as these number spaces are shared across all MSALs
* 0-99 Silent Flow
* 800-899 Auth Code Flow
* 900-999 Miscellaneous
*/
export const ApiId = {
acquireTokenRedirect: 861,
Expand All @@ -126,9 +126,35 @@ export const ApiId = {
acquireTokenSilent_silentFlow: 61,
logout: 961,
logoutPopup: 962,
hydrateCache: 963,
loadExternalTokens: 964,
} as const;
export type ApiId = (typeof ApiId)[keyof typeof ApiId];

/**
* API Names for Telemetry purposes.
*/
export const ApiName = {
861: "acquireTokenRedirect",
862: "acquireTokenPopup",
863: "ssoSilent",
864: "acquireTokenSilent_authCode",
865: "handleRedirectPromise",
866: "acquireTokenByCode",
61: "acquireTokenSilent_silentFlow",
961: "logout",
962: "logoutPopup",
963: "hydrateCache",
964: "loadExternalTokens",
} as const satisfies Record<ApiId, string>;

export const apiIdToName = (id: number | undefined): string => {
if (typeof id === "number" && id in ApiName) {
return ApiName[id as ApiId];
}
return "unknown";
};

/*
* Interaction type of the API - used for state and telemetry
*/
Expand Down
Loading