@equinor/fusion-framework-module-msal 8.0.4 → 8.0.5
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.
- package/CHANGELOG.md +24 -0
- package/dist/esm/MsalClient.js +7 -1
- package/dist/esm/MsalClient.js.map +1 -1
- package/dist/esm/MsalConfigurator.js +38 -1
- package/dist/esm/MsalConfigurator.js.map +1 -1
- package/dist/esm/__tests__/MsalConfigurator.test.js +23 -0
- package/dist/esm/__tests__/MsalConfigurator.test.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/MsalClient.d.ts +18 -1
- package/dist/types/MsalConfigurator.d.ts +25 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/MsalClient.ts +25 -1
- package/src/MsalConfigurator.ts +43 -1
- package/src/__tests__/MsalConfigurator.test.ts +41 -0
- package/src/version.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PublicClientApplication, type Configuration } from '@azure/msal-browser';
|
|
1
|
+
import { PublicClientApplication, type CacheLookupPolicy, type Configuration } from '@azure/msal-browser';
|
|
2
2
|
import type { IMsalClient, AcquireTokenResult, LoginOptions, LogoutOptions, LoginResult, AcquireTokenOptions } from './MsalClient.interface';
|
|
3
3
|
export type { IMsalClient };
|
|
4
4
|
/**
|
|
@@ -17,6 +17,23 @@ export type MsalClientConfig = Configuration & {
|
|
|
17
17
|
/** Optional tenant identifier for Azure AD tenant */
|
|
18
18
|
tenantId?: string;
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Cache lookup policy applied to every `acquireTokenSilent` call.
|
|
22
|
+
*
|
|
23
|
+
* Controls whether MSAL falls back to a hidden iframe when the refresh token
|
|
24
|
+
* fails. When `undefined`, MSAL's built-in default applies (cache → refresh
|
|
25
|
+
* token → iframe). Set to `CacheLookupPolicy.AccessTokenAndRefreshToken` to
|
|
26
|
+
* skip the iframe step and fail immediately with `InteractionRequiredAuthError`
|
|
27
|
+
* when the refresh token is revoked — avoiding the ~10–20 s
|
|
28
|
+
* `monitor_window_timeout` delay.
|
|
29
|
+
*
|
|
30
|
+
* When using {@link MsalConfigurator}, this defaults to
|
|
31
|
+
* `CacheLookupPolicy.AccessTokenAndRefreshToken`. When constructing `MsalClient`
|
|
32
|
+
* directly, the field is optional and defaults to `undefined` (MSAL default).
|
|
33
|
+
*
|
|
34
|
+
* Per-request `cacheLookupPolicy` on `SilentRequest` takes precedence over this value.
|
|
35
|
+
*/
|
|
36
|
+
cacheLookupPolicy?: CacheLookupPolicy;
|
|
20
37
|
};
|
|
21
38
|
/**
|
|
22
39
|
* MSAL v4 client implementation with extended properties and methods.
|
|
@@ -3,6 +3,7 @@ import { BaseConfigBuilder } from '@equinor/fusion-framework-module';
|
|
|
3
3
|
import type { IMsalProvider } from './MsalProvider.interface';
|
|
4
4
|
import { type ITelemetryProvider } from '@equinor/fusion-framework-module-telemetry';
|
|
5
5
|
import { type MsalClientConfig, type IMsalClient } from './MsalClient';
|
|
6
|
+
import { CacheLookupPolicy } from '@azure/msal-browser';
|
|
6
7
|
/**
|
|
7
8
|
* Telemetry configuration for MSAL module.
|
|
8
9
|
*
|
|
@@ -65,6 +66,30 @@ export declare class MsalConfigurator extends BaseConfigBuilder<MsalConfig> {
|
|
|
65
66
|
* ```
|
|
66
67
|
*/
|
|
67
68
|
setClientConfig(config?: MsalClientConfig): this;
|
|
69
|
+
/**
|
|
70
|
+
* Sets the cache lookup policy used for every silent token acquisition.
|
|
71
|
+
*
|
|
72
|
+
* Controls whether MSAL falls back to a hidden iframe when the refresh token
|
|
73
|
+
* fails. Defaults to `CacheLookupPolicy.AccessTokenAndRefreshToken`, which skips
|
|
74
|
+
* the iframe step and fails immediately with `InteractionRequiredAuthError` when
|
|
75
|
+
* the refresh token is revoked — avoiding the ~10–20 s `monitor_window_timeout`
|
|
76
|
+
* delay caused by MSAL's built-in iframe fallback.
|
|
77
|
+
*
|
|
78
|
+
* Set to `CacheLookupPolicy.Default` to restore MSAL's full waterfall:
|
|
79
|
+
* cache → refresh token → iframe.
|
|
80
|
+
*
|
|
81
|
+
* @param policy - Cache lookup policy to apply
|
|
82
|
+
* @returns The configurator instance for method chaining
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import { CacheLookupPolicy } from '@azure/msal-browser';
|
|
87
|
+
*
|
|
88
|
+
* // Restore MSAL's built-in iframe fallback (not recommended for most apps)
|
|
89
|
+
* configurator.setCacheLookupPolicy(CacheLookupPolicy.Default);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
setCacheLookupPolicy(policy: CacheLookupPolicy | undefined): this;
|
|
68
93
|
/**
|
|
69
94
|
* Sets a backend-issued authorization code for token exchange.
|
|
70
95
|
*
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "8.0.
|
|
1
|
+
export declare const version = "8.0.5";
|
package/package.json
CHANGED
package/src/MsalClient.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PublicClientApplication,
|
|
3
|
+
type CacheLookupPolicy,
|
|
3
4
|
type SilentRequest,
|
|
4
5
|
type Configuration,
|
|
5
6
|
type EndSessionRequest,
|
|
@@ -40,6 +41,23 @@ export type MsalClientConfig = Configuration & {
|
|
|
40
41
|
/** Optional tenant identifier for Azure AD tenant */
|
|
41
42
|
tenantId?: string;
|
|
42
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Cache lookup policy applied to every `acquireTokenSilent` call.
|
|
46
|
+
*
|
|
47
|
+
* Controls whether MSAL falls back to a hidden iframe when the refresh token
|
|
48
|
+
* fails. When `undefined`, MSAL's built-in default applies (cache → refresh
|
|
49
|
+
* token → iframe). Set to `CacheLookupPolicy.AccessTokenAndRefreshToken` to
|
|
50
|
+
* skip the iframe step and fail immediately with `InteractionRequiredAuthError`
|
|
51
|
+
* when the refresh token is revoked — avoiding the ~10–20 s
|
|
52
|
+
* `monitor_window_timeout` delay.
|
|
53
|
+
*
|
|
54
|
+
* When using {@link MsalConfigurator}, this defaults to
|
|
55
|
+
* `CacheLookupPolicy.AccessTokenAndRefreshToken`. When constructing `MsalClient`
|
|
56
|
+
* directly, the field is optional and defaults to `undefined` (MSAL default).
|
|
57
|
+
*
|
|
58
|
+
* Per-request `cacheLookupPolicy` on `SilentRequest` takes precedence over this value.
|
|
59
|
+
*/
|
|
60
|
+
cacheLookupPolicy?: CacheLookupPolicy;
|
|
43
61
|
};
|
|
44
62
|
|
|
45
63
|
/**
|
|
@@ -65,6 +83,7 @@ export type MsalClientConfig = Configuration & {
|
|
|
65
83
|
export class MsalClient extends PublicClientApplication implements IMsalClient {
|
|
66
84
|
#tenantId?: string;
|
|
67
85
|
#clientId?: string;
|
|
86
|
+
#cacheLookupPolicy?: CacheLookupPolicy;
|
|
68
87
|
|
|
69
88
|
/**
|
|
70
89
|
* Creates a new MSAL client instance.
|
|
@@ -75,6 +94,7 @@ export class MsalClient extends PublicClientApplication implements IMsalClient {
|
|
|
75
94
|
super(config);
|
|
76
95
|
this.#tenantId = config.auth?.tenantId;
|
|
77
96
|
this.#clientId = config.auth?.clientId;
|
|
97
|
+
this.#cacheLookupPolicy = config.cacheLookupPolicy;
|
|
78
98
|
}
|
|
79
99
|
|
|
80
100
|
/**
|
|
@@ -257,7 +277,11 @@ export class MsalClient extends PublicClientApplication implements IMsalClient {
|
|
|
257
277
|
'Attempting to acquire token silently',
|
|
258
278
|
request.correlationId || FUSION_CORRELATION_ID,
|
|
259
279
|
);
|
|
260
|
-
return await this.acquireTokenSilent(
|
|
280
|
+
return await this.acquireTokenSilent({
|
|
281
|
+
// Instance-level policy is the default; request-level cacheLookupPolicy takes precedence
|
|
282
|
+
cacheLookupPolicy: this.#cacheLookupPolicy,
|
|
283
|
+
...(request as SilentRequest),
|
|
284
|
+
});
|
|
261
285
|
} catch {
|
|
262
286
|
// Silent acquisition failed - fall back to interactive
|
|
263
287
|
this.getLogger().warning(
|
package/src/MsalConfigurator.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@equinor/fusion-framework-module-telemetry';
|
|
9
9
|
import { MsalClient, type MsalClientConfig, type IMsalClient } from './MsalClient';
|
|
10
10
|
import { createClientLogCallback } from './create-client-log-callback';
|
|
11
|
-
import { LogLevel } from '@azure/msal-browser';
|
|
11
|
+
import { CacheLookupPolicy, LogLevel } from '@azure/msal-browser';
|
|
12
12
|
import { version } from './version';
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -45,6 +45,13 @@ const MsalConfigSchema = z.object({
|
|
|
45
45
|
redirectUri: z.string().optional(),
|
|
46
46
|
loginHint: z.string().optional(),
|
|
47
47
|
authCode: z.string().optional(),
|
|
48
|
+
cacheLookupPolicy: z
|
|
49
|
+
.custom<CacheLookupPolicy>(
|
|
50
|
+
(val) =>
|
|
51
|
+
typeof val === 'number' &&
|
|
52
|
+
Object.values(CacheLookupPolicy).includes(val as CacheLookupPolicy),
|
|
53
|
+
)
|
|
54
|
+
.optional(),
|
|
48
55
|
version: z.string().transform((x: string) => String(semver.coerce(x))),
|
|
49
56
|
telemetry: TelemetryConfigSchema,
|
|
50
57
|
});
|
|
@@ -98,6 +105,8 @@ export class MsalConfigurator extends BaseConfigBuilder<MsalConfig> {
|
|
|
98
105
|
return telemetry;
|
|
99
106
|
}
|
|
100
107
|
});
|
|
108
|
+
// Default cache lookup policy to AccessTokenAndRefreshToken to avoid iframe fallback delays
|
|
109
|
+
this._set('cacheLookupPolicy', async () => CacheLookupPolicy.AccessTokenAndRefreshToken);
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
/**
|
|
@@ -125,6 +134,34 @@ export class MsalConfigurator extends BaseConfigBuilder<MsalConfig> {
|
|
|
125
134
|
return this;
|
|
126
135
|
}
|
|
127
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Sets the cache lookup policy used for every silent token acquisition.
|
|
139
|
+
*
|
|
140
|
+
* Controls whether MSAL falls back to a hidden iframe when the refresh token
|
|
141
|
+
* fails. Defaults to `CacheLookupPolicy.AccessTokenAndRefreshToken`, which skips
|
|
142
|
+
* the iframe step and fails immediately with `InteractionRequiredAuthError` when
|
|
143
|
+
* the refresh token is revoked — avoiding the ~10–20 s `monitor_window_timeout`
|
|
144
|
+
* delay caused by MSAL's built-in iframe fallback.
|
|
145
|
+
*
|
|
146
|
+
* Set to `CacheLookupPolicy.Default` to restore MSAL's full waterfall:
|
|
147
|
+
* cache → refresh token → iframe.
|
|
148
|
+
*
|
|
149
|
+
* @param policy - Cache lookup policy to apply
|
|
150
|
+
* @returns The configurator instance for method chaining
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* import { CacheLookupPolicy } from '@azure/msal-browser';
|
|
155
|
+
*
|
|
156
|
+
* // Restore MSAL's built-in iframe fallback (not recommended for most apps)
|
|
157
|
+
* configurator.setCacheLookupPolicy(CacheLookupPolicy.Default);
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
setCacheLookupPolicy(policy: CacheLookupPolicy | undefined): this {
|
|
161
|
+
this._set('cacheLookupPolicy', async () => policy);
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
|
|
128
165
|
/**
|
|
129
166
|
* Sets a backend-issued authorization code for token exchange.
|
|
130
167
|
*
|
|
@@ -346,6 +383,11 @@ export class MsalConfigurator extends BaseConfigBuilder<MsalConfig> {
|
|
|
346
383
|
},
|
|
347
384
|
};
|
|
348
385
|
}
|
|
386
|
+
// Apply silent cache lookup policy if configured
|
|
387
|
+
if (config.cacheLookupPolicy !== undefined) {
|
|
388
|
+
clientConfig.cacheLookupPolicy = config.cacheLookupPolicy;
|
|
389
|
+
}
|
|
390
|
+
|
|
349
391
|
// Instantiate MSAL client with fully configured options
|
|
350
392
|
config.client = new MsalClient(clientConfig);
|
|
351
393
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ConfigBuilderCallbackArgs } from '@equinor/fusion-framework-module';
|
|
2
|
+
import { CacheLookupPolicy } from '@azure/msal-browser';
|
|
2
3
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
4
|
import type { IMsalClient } from '../MsalClient.interface';
|
|
4
5
|
import { type MsalConfig, MsalConfigurator } from '../MsalConfigurator';
|
|
@@ -72,4 +73,44 @@ describe('MsalConfigurator', () => {
|
|
|
72
73
|
|
|
73
74
|
expect(config.client).toBeUndefined();
|
|
74
75
|
});
|
|
76
|
+
|
|
77
|
+
describe('cacheLookupPolicy', () => {
|
|
78
|
+
it('defaults to CacheLookupPolicy.AccessTokenAndRefreshToken', async () => {
|
|
79
|
+
const configurator = new MsalConfigurator();
|
|
80
|
+
configurator.setClient(createClient());
|
|
81
|
+
|
|
82
|
+
const config = await configurator.createConfigAsync(
|
|
83
|
+
createConfigCallbackArgs(),
|
|
84
|
+
createInitialConfig(),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(config.cacheLookupPolicy).toBe(CacheLookupPolicy.AccessTokenAndRefreshToken);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('setCacheLookupPolicy(undefined) clears the policy so MSAL default applies', async () => {
|
|
91
|
+
const configurator = new MsalConfigurator();
|
|
92
|
+
configurator.setClient(createClient());
|
|
93
|
+
configurator.setCacheLookupPolicy(undefined);
|
|
94
|
+
|
|
95
|
+
const config = await configurator.createConfigAsync(
|
|
96
|
+
createConfigCallbackArgs(),
|
|
97
|
+
createInitialConfig(),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(config.cacheLookupPolicy).toBeUndefined();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('setCacheLookupPolicy overrides the default', async () => {
|
|
104
|
+
const configurator = new MsalConfigurator();
|
|
105
|
+
configurator.setClient(createClient());
|
|
106
|
+
configurator.setCacheLookupPolicy(CacheLookupPolicy.Default);
|
|
107
|
+
|
|
108
|
+
const config = await configurator.createConfigAsync(
|
|
109
|
+
createConfigCallbackArgs(),
|
|
110
|
+
createInitialConfig(),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(config.cacheLookupPolicy).toBe(CacheLookupPolicy.Default);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
75
116
|
});
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '8.0.
|
|
2
|
+
export const version = '8.0.5';
|