Skip to content

Commit 0f4a5fc

Browse files
Add silentRefreshReason telemetry field to PerformanceEvent (#8336)
Add silentRefreshReason telemetry field to PerformanceEvent
1 parent ea3d205 commit 0f4a5fc

6 files changed

Lines changed: 173 additions & 0 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Add silentRefreshReason telemetry field to PerformanceEvent #8336",
4+
"packageName": "@azure/msal-browser",
5+
"email": "kshabelko@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Add silentRefreshReason telemetry field to PerformanceEvent #8336",
4+
"packageName": "@azure/msal-common",
5+
"email": "kshabelko@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

lib/msal-browser/src/controllers/StandardController.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,15 @@ export class StandardController implements IController {
20442044
);
20452045

20462046
if (shouldTryToResolveSilently) {
2047+
const silentRefreshReason = `${refreshTokenError.errorCode}${
2048+
refreshTokenError.subError
2049+
? `|${refreshTokenError.subError}`
2050+
: ""
2051+
}`;
2052+
this.performanceClient.addFields(
2053+
{ silentRefreshReason },
2054+
request.correlationId
2055+
);
20472056
if (!this.activeIframeRequest) {
20482057
let _resolve: (result: boolean) => void;
20492058
// Always set the active request tracker immediately after checking it to prevent races

lib/msal-browser/test/app/PublicClientApplication.spec.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5817,6 +5817,144 @@ describe("PublicClientApplication.ts Class Unit Tests", () => {
58175817
expect(silentRefreshSpy).toHaveBeenCalledTimes(0);
58185818
expect(silentIframeSpy).toHaveBeenCalledTimes(1);
58195819
});
5820+
5821+
describe("silentRefreshReason telemetry", () => {
5822+
it("adds silentRefreshReason telemetry field with errorCode when refresh token error triggers iframe fallback", (done) => {
5823+
jest.spyOn(
5824+
SilentCacheClient.prototype,
5825+
"acquireToken"
5826+
).mockRejectedValue(refreshRequiredCacheError);
5827+
jest.spyOn(
5828+
SilentRefreshClient.prototype,
5829+
"acquireToken"
5830+
).mockRejectedValue(refreshRequiredServerError);
5831+
jest.spyOn(
5832+
SilentIframeClient.prototype,
5833+
"acquireToken"
5834+
).mockResolvedValue(testTokenResponse);
5835+
5836+
const callbackId = pca.addPerformanceCallback((events) => {
5837+
expect(events[0].silentRefreshReason).toBe(
5838+
BrowserConstants.INVALID_GRANT_ERROR
5839+
);
5840+
pca.removePerformanceCallback(callbackId);
5841+
done();
5842+
});
5843+
5844+
pca.acquireTokenSilent({
5845+
scopes: ["openid"],
5846+
account: testAccount,
5847+
cacheLookupPolicy: CacheLookupPolicy.Default,
5848+
correlationId: RANDOM_TEST_GUID,
5849+
});
5850+
});
5851+
5852+
it("adds silentRefreshReason telemetry field with errorCode and subError when subError is present", (done) => {
5853+
const errorWithSubError = new ServerError(
5854+
BrowserConstants.INVALID_GRANT_ERROR,
5855+
"Refresh Token expired",
5856+
"bad_token"
5857+
);
5858+
5859+
jest.spyOn(
5860+
SilentCacheClient.prototype,
5861+
"acquireToken"
5862+
).mockRejectedValue(refreshRequiredCacheError);
5863+
jest.spyOn(
5864+
SilentRefreshClient.prototype,
5865+
"acquireToken"
5866+
).mockRejectedValue(errorWithSubError);
5867+
jest.spyOn(
5868+
SilentIframeClient.prototype,
5869+
"acquireToken"
5870+
).mockResolvedValue(testTokenResponse);
5871+
5872+
const callbackId = pca.addPerformanceCallback((events) => {
5873+
expect(events[0].silentRefreshReason).toBe(
5874+
`${BrowserConstants.INVALID_GRANT_ERROR}|bad_token`
5875+
);
5876+
pca.removePerformanceCallback(callbackId);
5877+
done();
5878+
});
5879+
5880+
pca.acquireTokenSilent({
5881+
scopes: ["openid"],
5882+
account: testAccount,
5883+
cacheLookupPolicy: CacheLookupPolicy.Default,
5884+
correlationId: RANDOM_TEST_GUID,
5885+
});
5886+
});
5887+
5888+
it("adds silentRefreshReason telemetry field with refreshTokenExpired error code", (done) => {
5889+
const refreshTokenExpiredError =
5890+
createInteractionRequiredAuthError(
5891+
InteractionRequiredAuthErrorCodes.refreshTokenExpired
5892+
);
5893+
5894+
jest.spyOn(
5895+
SilentCacheClient.prototype,
5896+
"acquireToken"
5897+
).mockRejectedValue(refreshRequiredCacheError);
5898+
jest.spyOn(
5899+
SilentRefreshClient.prototype,
5900+
"acquireToken"
5901+
).mockRejectedValue(refreshTokenExpiredError);
5902+
jest.spyOn(
5903+
SilentIframeClient.prototype,
5904+
"acquireToken"
5905+
).mockResolvedValue(testTokenResponse);
5906+
5907+
const callbackId = pca.addPerformanceCallback((events) => {
5908+
expect(events[0].silentRefreshReason).toBe(
5909+
InteractionRequiredAuthErrorCodes.refreshTokenExpired
5910+
);
5911+
pca.removePerformanceCallback(callbackId);
5912+
done();
5913+
});
5914+
5915+
pca.acquireTokenSilent({
5916+
scopes: ["openid"],
5917+
account: testAccount,
5918+
cacheLookupPolicy: CacheLookupPolicy.Default,
5919+
correlationId: RANDOM_TEST_GUID,
5920+
});
5921+
});
5922+
5923+
it("adds silentRefreshReason telemetry field with noTokensFound error code", (done) => {
5924+
const noTokensFoundError =
5925+
createInteractionRequiredAuthError(
5926+
InteractionRequiredAuthErrorCodes.noTokensFound
5927+
);
5928+
5929+
jest.spyOn(
5930+
SilentCacheClient.prototype,
5931+
"acquireToken"
5932+
).mockRejectedValue(refreshRequiredCacheError);
5933+
jest.spyOn(
5934+
SilentRefreshClient.prototype,
5935+
"acquireToken"
5936+
).mockRejectedValue(noTokensFoundError);
5937+
jest.spyOn(
5938+
SilentIframeClient.prototype,
5939+
"acquireToken"
5940+
).mockResolvedValue(testTokenResponse);
5941+
5942+
const callbackId = pca.addPerformanceCallback((events) => {
5943+
expect(events[0].silentRefreshReason).toBe(
5944+
InteractionRequiredAuthErrorCodes.noTokensFound
5945+
);
5946+
pca.removePerformanceCallback(callbackId);
5947+
done();
5948+
});
5949+
5950+
pca.acquireTokenSilent({
5951+
scopes: ["openid"],
5952+
account: testAccount,
5953+
cacheLookupPolicy: CacheLookupPolicy.Default,
5954+
correlationId: RANDOM_TEST_GUID,
5955+
});
5956+
});
5957+
});
58205958
});
58215959
});
58225960

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3487,6 +3487,7 @@ export type PerformanceEvent = {
34873487
navigateCallbackResult?: boolean;
34883488
dataBoundary?: DataBoundary;
34893489
logs?: string;
3490+
silentRefreshReason?: string;
34903491
};
34913492

34923493
declare namespace PerformanceEvents {
@@ -4875,5 +4876,8 @@ const X_MS_LIB_CAPABILITY_VALUE: string;
48754876
// src/telemetry/performance/PerformanceEvent.ts:310:21 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
48764877
// src/telemetry/performance/PerformanceEvent.ts:310:14 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
48774878
// src/telemetry/performance/PerformanceEvent.ts:310:8 - (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration
4879+
// src/telemetry/performance/PerformanceEvent.ts:351:22 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
4880+
// src/telemetry/performance/PerformanceEvent.ts:351:14 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@"
4881+
// src/telemetry/performance/PerformanceEvent.ts:351:8 - (tsdoc-undefined-tag) The TSDoc tag "@type" is not defined in this configuration
48784882

48794883
```

lib/msal-common/src/telemetry/performance/PerformanceEvent.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,14 @@ export type PerformanceEvent = {
343343

344344
// Hashed logs in the format [millis1,hash1;millis2,hash2;...]
345345
logs?: string;
346+
347+
/**
348+
* Reason for silent refresh fallback to iframe
349+
* Format: errorCode or errorCode|subError
350+
*
351+
* @type {?string}
352+
*/
353+
silentRefreshReason?: string;
346354
};
347355

348356
export type PerformanceEventContext = {

0 commit comments

Comments
 (0)