@equinor/fusion-framework-module-msal 11.0.0 → 11.0.1
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/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +8 -5
- package/CHANGELOG.md +0 -1212
- package/docs/api-reference.md +0 -85
- package/docs/auth-code-flow.md +0 -86
- package/docs/migration-v2-to-v4.md +0 -115
- package/docs/testing.md +0 -191
- package/docs/troubleshooting.md +0 -17
- package/docs/version-management.md +0 -67
- package/src/MsalClient.interface.ts +0 -139
- package/src/MsalClient.ts +0 -326
- package/src/MsalConfigurator.ts +0 -486
- package/src/MsalProvider.interface.ts +0 -179
- package/src/MsalProvider.ts +0 -776
- package/src/MsalProxyProvider.interface.ts +0 -72
- package/src/__tests__/MsalConfigurator.test.ts +0 -222
- package/src/__tests__/MsalProvider.test.ts +0 -74
- package/src/__tests__/create-proxy-provider.test.ts +0 -77
- package/src/__tests__/mock/create-mock-user-from-token.test.ts +0 -46
- package/src/__tests__/mock/msal-mock.test.ts +0 -613
- package/src/__tests__/versioning/resolve-version.test.ts +0 -161
- package/src/create-client-log-callback.ts +0 -102
- package/src/create-proxy-provider.ts +0 -97
- package/src/index.ts +0 -48
- package/src/mock/MsalMockClient.ts +0 -618
- package/src/mock/MsalMockConfigurator.ts +0 -305
- package/src/mock/create-mock-token.ts +0 -92
- package/src/mock/create-mock-user-from-token.ts +0 -46
- package/src/mock/create-msal-mock-client.ts +0 -25
- package/src/mock/decode-jwt-segment.ts +0 -22
- package/src/mock/index.ts +0 -30
- package/src/mock/module.ts +0 -54
- package/src/module.ts +0 -142
- package/src/msal-config-schema.ts +0 -81
- package/src/static.ts +0 -38
- package/src/telemetry-config-schema.ts +0 -25
- package/src/types.ts +0 -16
- package/src/util/compare-origin.ts +0 -18
- package/src/util/normalize-uri.ts +0 -24
- package/src/util/redirect.ts +0 -19
- package/src/v2/IAuthClient.interface.ts +0 -114
- package/src/v2/Logger.ts +0 -204
- package/src/v2/MsalProvider.interface.ts +0 -102
- package/src/v2/create-proxy-client.ts +0 -195
- package/src/v2/create-proxy-provider.ts +0 -177
- package/src/v2/map-account-info.ts +0 -23
- package/src/v2/map-authentication-result.ts +0 -28
- package/src/v2/types.ts +0 -674
- package/src/v4/create-proxy-provider.ts +0 -75
- package/src/v4/index.ts +0 -13
- package/src/v4/types.ts +0 -727
- package/src/version.ts +0 -2
- package/src/versioning/VersionError.ts +0 -64
- package/src/versioning/index.ts +0 -29
- package/src/versioning/resolve-version.ts +0 -154
- package/src/versioning/types.ts +0 -60
- package/tsconfig.json +0 -18
- package/vitest.config.ts +0 -11
package/src/MsalConfigurator.ts
DELETED
|
@@ -1,486 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BaseConfigBuilder,
|
|
3
|
-
type ConfigBuilderCallbackArgs,
|
|
4
|
-
} from '@equinor/fusion-framework-module';
|
|
5
|
-
import { TelemetryLevel } from '@equinor/fusion-framework-module-telemetry';
|
|
6
|
-
import { CacheLookupPolicy, LogLevel } from '@azure/msal-browser';
|
|
7
|
-
|
|
8
|
-
import type { ITelemetryProvider } from '@equinor/fusion-framework-module-telemetry';
|
|
9
|
-
import type { IMsalProvider } from './MsalProvider.interface';
|
|
10
|
-
import { MsalClient, type MsalClientConfig, type IMsalClient } from './MsalClient';
|
|
11
|
-
import { createClientLogCallback } from './create-client-log-callback';
|
|
12
|
-
import { version } from './version';
|
|
13
|
-
import { MsalConfigSchema, type MsalConfig } from './msal-config-schema';
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
MsalConfigSchema,
|
|
17
|
-
type MsalConfig,
|
|
18
|
-
type MsalConfigExtension,
|
|
19
|
-
} from './msal-config-schema';
|
|
20
|
-
export { TelemetryConfigSchema, type TelemetryConfig } from './telemetry-config-schema';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Configuration builder for MSAL v4 authentication module.
|
|
24
|
-
*
|
|
25
|
-
* This configurator provides a fluent API for setting up Microsoft Authentication Library
|
|
26
|
-
* configuration with support for MSAL v4 features and breaking changes.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* ```typescript
|
|
30
|
-
* const configurator = new MsalConfigurator();
|
|
31
|
-
* configurator.setClient(new AuthClient('your-tenant-id', 'your-client-id'));
|
|
32
|
-
* configurator.setRequiresAuth(true);
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export class MsalConfigurator extends BaseConfigBuilder<MsalConfig> {
|
|
36
|
-
#msalConfig?: MsalClientConfig;
|
|
37
|
-
#client?: IMsalClient;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The MSAL module version being configured.
|
|
41
|
-
*
|
|
42
|
-
* @default Latest
|
|
43
|
-
* @returns The configured MSAL module version.
|
|
44
|
-
*/
|
|
45
|
-
public get version(): string {
|
|
46
|
-
return version;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Creates a new MSAL configurator instance.
|
|
51
|
-
*
|
|
52
|
-
* Sets up default configuration including version and telemetry provider integration.
|
|
53
|
-
*/
|
|
54
|
-
constructor() {
|
|
55
|
-
super();
|
|
56
|
-
// Set default version
|
|
57
|
-
this._set('version', async () => this.version);
|
|
58
|
-
// Auto-detect and integrate telemetry module if available
|
|
59
|
-
this._set('telemetry.provider', async (args) => {
|
|
60
|
-
// Only resolve the telemetry instance when the telemetry module is registered
|
|
61
|
-
if (args.hasModule('telemetry')) {
|
|
62
|
-
const telemetry = await args.requireInstance('telemetry');
|
|
63
|
-
return telemetry;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
// Always resolve the configured client instance through the builder.
|
|
67
|
-
// This keeps the client getter live and avoids re-registering the same config key.
|
|
68
|
-
this._set('client', async () => this.#client);
|
|
69
|
-
// Default cache lookup policy to AccessTokenAndRefreshToken to avoid iframe fallback delays
|
|
70
|
-
this._set('cacheLookupPolicy', async () => CacheLookupPolicy.AccessTokenAndRefreshToken);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Sets the MSAL client configuration for authentication.
|
|
75
|
-
*
|
|
76
|
-
* This method stores the configuration which will be used to create an MSAL client
|
|
77
|
-
* instance during module initialization. The client will be auto-created if not provided
|
|
78
|
-
* via `setClient`.
|
|
79
|
-
*
|
|
80
|
-
* @param config - Client configuration object with MSAL settings (client ID, tenant ID, etc.)
|
|
81
|
-
* @returns The configurator instance for method chaining
|
|
82
|
-
*
|
|
83
|
-
* @example
|
|
84
|
-
* ```typescript
|
|
85
|
-
* configurator.setClientConfig({
|
|
86
|
-
* auth: {
|
|
87
|
-
* clientId: 'your-client-id',
|
|
88
|
-
* tenantId: 'your-tenant-id'
|
|
89
|
-
* }
|
|
90
|
-
* });
|
|
91
|
-
* ```
|
|
92
|
-
*/
|
|
93
|
-
setClientConfig(config?: MsalClientConfig): this {
|
|
94
|
-
this.#msalConfig = config;
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Returns the client configuration declared through
|
|
100
|
-
* {@link MsalConfigurator.setClientConfig | setClientConfig}, if any.
|
|
101
|
-
*
|
|
102
|
-
* @remarks
|
|
103
|
-
* This is the configuration as declared, not the resolved one a client is
|
|
104
|
-
* built from — see
|
|
105
|
-
* {@link MsalConfigurator._createClientConfig | _createClientConfig} for that.
|
|
106
|
-
* Reading it is how a subclass can tell "nothing was declared" apart from
|
|
107
|
-
* "declared, and here it is", without re-deriving that from a resolved value.
|
|
108
|
-
*
|
|
109
|
-
* @returns The declared client configuration, or `undefined` when none was declared.
|
|
110
|
-
*/
|
|
111
|
-
public getClientConfig(): MsalClientConfig | undefined {
|
|
112
|
-
return this.#msalConfig;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Sets the cache lookup policy used for every silent token acquisition.
|
|
117
|
-
*
|
|
118
|
-
* Controls whether MSAL falls back to a hidden iframe when the refresh token
|
|
119
|
-
* fails. Defaults to `CacheLookupPolicy.AccessTokenAndRefreshToken`, which skips
|
|
120
|
-
* the iframe step and fails immediately with `InteractionRequiredAuthError` when
|
|
121
|
-
* the refresh token is revoked — avoiding the ~10–20 s `monitor_window_timeout`
|
|
122
|
-
* delay caused by MSAL's built-in iframe fallback.
|
|
123
|
-
*
|
|
124
|
-
* Set to `CacheLookupPolicy.Default` to restore MSAL's full waterfall:
|
|
125
|
-
* cache → refresh token → iframe.
|
|
126
|
-
*
|
|
127
|
-
* @param policy - Cache lookup policy to apply
|
|
128
|
-
* @returns The configurator instance for method chaining
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* ```typescript
|
|
132
|
-
* import { CacheLookupPolicy } from '@azure/msal-browser';
|
|
133
|
-
*
|
|
134
|
-
* // Restore MSAL's built-in iframe fallback (not recommended for most apps)
|
|
135
|
-
* configurator.setCacheLookupPolicy(CacheLookupPolicy.Default);
|
|
136
|
-
* ```
|
|
137
|
-
*/
|
|
138
|
-
setCacheLookupPolicy(policy: CacheLookupPolicy | undefined): this {
|
|
139
|
-
this._set('cacheLookupPolicy', async () => policy);
|
|
140
|
-
return this;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Sets a backend-issued authorization code for token exchange.
|
|
145
|
-
*
|
|
146
|
-
* This enables the MSAL module to exchange a backend-generated auth code for tokens
|
|
147
|
-
* during initialization, allowing users to be automatically signed in without triggering
|
|
148
|
-
* an interactive MSAL login flow. The auth code is exchanged before the requiresAuth check,
|
|
149
|
-
* so tokens are cached and no login prompt appears.
|
|
150
|
-
*
|
|
151
|
-
* This follows Microsoft's standard SPA Auth Code Flow pattern and is compatible with
|
|
152
|
-
* MSAL Browser's acquireTokenByCode() method.
|
|
153
|
-
*
|
|
154
|
-
* @param authCode - The authorization code issued by the backend, or undefined to clear/reset it
|
|
155
|
-
* @returns The configurator instance for method chaining
|
|
156
|
-
*
|
|
157
|
-
* @example
|
|
158
|
-
* ```typescript
|
|
159
|
-
* // Backend provides auth code in HTML/config
|
|
160
|
-
* const config = { auth: { code: getAuthCodeFromBackend() } };
|
|
161
|
-
* configurator.setAuthCode(config.auth.code);
|
|
162
|
-
*
|
|
163
|
-
* // Clear previously configured auth code
|
|
164
|
-
* configurator.setAuthCode(undefined);
|
|
165
|
-
* ```
|
|
166
|
-
*
|
|
167
|
-
* @remarks
|
|
168
|
-
* - Auth codes are single-use and short-lived (typically 5-10 minutes)
|
|
169
|
-
* - The exchange happens during module initialization before requiresAuth check
|
|
170
|
-
* - If exchange fails, the provider falls back to standard MSAL authentication flows
|
|
171
|
-
* - Passing undefined, empty, or whitespace-only values clears the configured auth code
|
|
172
|
-
* - Requires backend to be configured with SPA Auth Code support
|
|
173
|
-
*/
|
|
174
|
-
setAuthCode(authCode?: string): this {
|
|
175
|
-
const normalizedAuthCode = authCode?.trim() || undefined;
|
|
176
|
-
this._set('authCode', async () => normalizedAuthCode);
|
|
177
|
-
return this;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Sets whether authentication is required for the application.
|
|
182
|
-
*
|
|
183
|
-
* When set to true, the application will attempt automatic login during initialization
|
|
184
|
-
* if no valid authentication session exists. When false, authentication is optional
|
|
185
|
-
* and must be triggered manually.
|
|
186
|
-
*
|
|
187
|
-
* @param requiresAuth - Whether authentication is mandatory for the application
|
|
188
|
-
* @returns The configurator instance for method chaining
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* ```typescript
|
|
192
|
-
* // Require authentication on app load
|
|
193
|
-
* configurator.setRequiresAuth(true);
|
|
194
|
-
*
|
|
195
|
-
* // Make authentication optional
|
|
196
|
-
* configurator.setRequiresAuth(false);
|
|
197
|
-
* ```
|
|
198
|
-
*/
|
|
199
|
-
setRequiresAuth(requiresAuth: boolean): this {
|
|
200
|
-
this._set('requiresAuth', async () => requiresAuth);
|
|
201
|
-
return this;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Sets a default login hint for authentication flows.
|
|
206
|
-
*
|
|
207
|
-
* The login hint is used to pre-fill the username during authentication and
|
|
208
|
-
* enables silent SSO when no account is available.
|
|
209
|
-
*
|
|
210
|
-
* @param loginHint - The preferred username/email to use as login hint
|
|
211
|
-
* @returns The configurator instance for method chaining
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* ```typescript
|
|
215
|
-
* configurator.setLoginHint('user@company.com');
|
|
216
|
-
* ```
|
|
217
|
-
*/
|
|
218
|
-
setLoginHint(loginHint?: string): this {
|
|
219
|
-
this._set('loginHint', async () => loginHint);
|
|
220
|
-
return this;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Sets a pre-configured MSAL provider instance directly.
|
|
225
|
-
*
|
|
226
|
-
* @deprecated Since version 5.1.0. Use {@link MsalConfigurator.setClient | setClient} instead.
|
|
227
|
-
*
|
|
228
|
-
* @param provider - Pre-configured provider instance, or undefined to clear
|
|
229
|
-
* @returns The configurator instance for method chaining
|
|
230
|
-
*/
|
|
231
|
-
setProvider(provider?: IMsalProvider): this {
|
|
232
|
-
this._set('provider', async () => provider);
|
|
233
|
-
return this;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Sets a pre-configured MSAL client instance.
|
|
238
|
-
*
|
|
239
|
-
* This method allows you to provide an already-instantiated MSAL client rather than
|
|
240
|
-
* letting the configurator create one from configuration. Useful when you need
|
|
241
|
-
* custom client configuration outside the standard configurator options.
|
|
242
|
-
*
|
|
243
|
-
* @param client - Pre-configured MSAL client instance
|
|
244
|
-
* @returns The configurator instance for method chaining
|
|
245
|
-
*
|
|
246
|
-
* @example
|
|
247
|
-
* ```typescript
|
|
248
|
-
* const customClient = new MsalClient(customConfig);
|
|
249
|
-
* configurator.setClient(customClient);
|
|
250
|
-
* ```
|
|
251
|
-
*/
|
|
252
|
-
setClient(client: IMsalClient): this {
|
|
253
|
-
this.#client = client;
|
|
254
|
-
return this;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Returns the currently configured MSAL client, if one has been set.
|
|
259
|
-
*
|
|
260
|
-
* @remarks
|
|
261
|
-
* This is useful in tests when a mock client has been provided and the test
|
|
262
|
-
* wants to adjust its state after it has been assigned to the configurator.
|
|
263
|
-
*
|
|
264
|
-
* @returns The configured client, or `undefined` when none has been set.
|
|
265
|
-
*/
|
|
266
|
-
public getClient(): IMsalClient | undefined {
|
|
267
|
-
return this.#client;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Sets telemetry provider for MSAL authentication events.
|
|
272
|
-
*
|
|
273
|
-
* This allows MSAL authentication events to be tracked through the framework's
|
|
274
|
-
* telemetry system. If not provided, telemetry module will be auto-detected if
|
|
275
|
-
* available in the framework configuration.
|
|
276
|
-
*
|
|
277
|
-
* @param telemetry - Telemetry provider instance or undefined to disable telemetry
|
|
278
|
-
* @returns The configurator instance for method chaining
|
|
279
|
-
*/
|
|
280
|
-
setTelemetry(telemetry: ITelemetryProvider | undefined): this {
|
|
281
|
-
this._set('telemetry.provider', async () => telemetry);
|
|
282
|
-
return this;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Sets optional metadata to be included on all MSAL telemetry events.
|
|
287
|
-
*
|
|
288
|
-
* @deprecated Use {@link MsalConfigurator.setTelemetry | setTelemetry} instead.
|
|
289
|
-
*
|
|
290
|
-
* @param metadata - Key-value metadata to attach to telemetry events, or undefined to clear
|
|
291
|
-
* @returns The configurator instance for method chaining
|
|
292
|
-
*/
|
|
293
|
-
setTelemetryMetadata(metadata: Record<string, unknown> | undefined): this {
|
|
294
|
-
this._set('telemetry.metadata', async () => metadata);
|
|
295
|
-
return this;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Sets the telemetry scope for MSAL authentication events.
|
|
300
|
-
*
|
|
301
|
-
* The scope is used to categorize and filter telemetry events in the telemetry system.
|
|
302
|
-
* Default scope is ['framework', 'authentication'].
|
|
303
|
-
*
|
|
304
|
-
* @param scope - Array of scope identifiers for telemetry categorization
|
|
305
|
-
* @returns The configurator instance for method chaining
|
|
306
|
-
*
|
|
307
|
-
* @example
|
|
308
|
-
* ```typescript
|
|
309
|
-
* configurator.setTelemetryScope(['custom', 'auth', 'msal']);
|
|
310
|
-
* ```
|
|
311
|
-
*/
|
|
312
|
-
setTelemetryScope(scope: string[]): this {
|
|
313
|
-
this._set('telemetry.scope', async () => scope);
|
|
314
|
-
return this;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Processes and validates the configuration.
|
|
319
|
-
*
|
|
320
|
-
* @param rawConfig - Raw configuration object
|
|
321
|
-
* @param init - The builder arguments, carrying the host reference when hoisted
|
|
322
|
-
* @returns Processed and validated configuration
|
|
323
|
-
*/
|
|
324
|
-
async _processConfig(
|
|
325
|
-
rawConfig: MsalConfig,
|
|
326
|
-
init?: ConfigBuilderCallbackArgs,
|
|
327
|
-
): Promise<MsalConfig> {
|
|
328
|
-
// Validate and coerce configuration using Zod schema
|
|
329
|
-
const config = await MsalConfigSchema.parseAsync(rawConfig);
|
|
330
|
-
|
|
331
|
-
// Auto-create client if no client instance was supplied
|
|
332
|
-
// This allows users to provide configuration without manually instantiating the client
|
|
333
|
-
// A hoisted module authenticates through the host's provider, so any client built here
|
|
334
|
-
// would be discarded — gate it here rather than in `_createClient`, so a substituted
|
|
335
|
-
// client (see `MsalMockConfigurator`) cannot shadow the host's signed-in user
|
|
336
|
-
if (!config.client && !this._isHoisted(init)) {
|
|
337
|
-
config.client = await this._createClient(config, init);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return config;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Creates the client to authenticate through, when none was supplied.
|
|
345
|
-
*
|
|
346
|
-
* @remarks
|
|
347
|
-
* Called by {@link MsalConfigurator._processConfig | _processConfig} only when
|
|
348
|
-
* no client was set, so a client supplied through
|
|
349
|
-
* {@link MsalConfigurator.setClient | setClient} always wins. It is likewise
|
|
350
|
-
* not called when the module is hoisted onto a host application's provider —
|
|
351
|
-
* see {@link MsalConfigurator._isHoisted | _isHoisted}.
|
|
352
|
-
*
|
|
353
|
-
* This is the seam for authenticating through something other than Entra ID.
|
|
354
|
-
* Overriding it replaces only the client, leaving the builder, the schema
|
|
355
|
-
* validation and `MsalProvider` untouched — which is how
|
|
356
|
-
* `MsalMockConfigurator` substitutes an in-process client for tests.
|
|
357
|
-
*
|
|
358
|
-
* An override normally builds from
|
|
359
|
-
* {@link MsalConfigurator._createClientConfig | _createClientConfig}, so it
|
|
360
|
-
* receives the same fully-resolved {@link MsalClientConfig} the real client is
|
|
361
|
-
* built from rather than re-deriving it.
|
|
362
|
-
*
|
|
363
|
-
* Returning `undefined` is legitimate and means "there is nothing to build a
|
|
364
|
-
* client from", which leaves the module without one.
|
|
365
|
-
*
|
|
366
|
-
* @param config - The validated configuration the client is built from.
|
|
367
|
-
* @param init - The builder arguments, carrying the host reference when hoisted.
|
|
368
|
-
* @returns The client, or `undefined` when there is nothing to build one from.
|
|
369
|
-
*/
|
|
370
|
-
protected async _createClient(
|
|
371
|
-
config: MsalConfig,
|
|
372
|
-
_init?: ConfigBuilderCallbackArgs,
|
|
373
|
-
): Promise<IMsalClient | undefined> {
|
|
374
|
-
const clientConfig = this._createClientConfig(config);
|
|
375
|
-
// A client can be omitted for a hoisted module or an intentionally incomplete setup.
|
|
376
|
-
if (!clientConfig) {
|
|
377
|
-
return undefined;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Instantiate MSAL client with fully configured options
|
|
381
|
-
return new MsalClient(clientConfig);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Whether this module is hoisted onto a host application's authentication.
|
|
386
|
-
*
|
|
387
|
-
* @remarks
|
|
388
|
-
* When an application runs inside a host — a portal loading an app, or an app
|
|
389
|
-
* loading a widget — the module initializer returns a proxy of the host's
|
|
390
|
-
* provider instead of building its own (see the host-provider branch of the
|
|
391
|
-
* module initializer). A client built during configuration would therefore be
|
|
392
|
-
* constructed and immediately discarded.
|
|
393
|
-
*
|
|
394
|
-
* Detecting this during configuration lets the configurator skip building a
|
|
395
|
-
* client entirely, which matters most for substituted clients: a mock client
|
|
396
|
-
* built here would otherwise silently shadow the host's real signed-in user.
|
|
397
|
-
*
|
|
398
|
-
* @param init - The builder arguments, carrying the host reference when hoisted.
|
|
399
|
-
* @returns `true` when a host provider will be used instead of a locally built client.
|
|
400
|
-
*/
|
|
401
|
-
protected _isHoisted(init?: ConfigBuilderCallbackArgs): boolean {
|
|
402
|
-
return !!(init?.ref as { auth?: IMsalProvider } | undefined)?.auth;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Resolves the full MSAL client configuration to build a client from.
|
|
407
|
-
*
|
|
408
|
-
* @remarks
|
|
409
|
-
* Applies the defaults a client is expected to be built with — authority
|
|
410
|
-
* derived from the tenant, cache location, telemetry-backed logging and the
|
|
411
|
-
* configured cache lookup policy.
|
|
412
|
-
*
|
|
413
|
-
* Kept separate from {@link MsalConfigurator._createClient | _createClient} so
|
|
414
|
-
* that substituting the client does not also mean re-implementing this
|
|
415
|
-
* resolution. `MsalMockConfigurator` relies on it to hand its mock client the
|
|
416
|
-
* very same configuration the real client would have received.
|
|
417
|
-
*
|
|
418
|
-
* @param config - The validated configuration.
|
|
419
|
-
* @returns The client configuration, or `undefined` when none was declared.
|
|
420
|
-
*/
|
|
421
|
-
protected _createClientConfig(config: MsalConfig): MsalClientConfig | undefined {
|
|
422
|
-
const declared = this.#msalConfig;
|
|
423
|
-
// Do not construct a client when configuration has not supplied client settings.
|
|
424
|
-
if (!declared) {
|
|
425
|
-
return undefined;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
config.telemetry.provider?.trackEvent({
|
|
429
|
-
name: 'module-msal.configurator._processConfig.creating-client',
|
|
430
|
-
level: TelemetryLevel.Debug,
|
|
431
|
-
scope: config.telemetry.scope,
|
|
432
|
-
metadata: { ...config.telemetry.metadata, clientConfig: declared },
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
// Copied rather than enriched in place, so the object a caller passed to
|
|
436
|
-
// `setClientConfig` is never rewritten behind its back — a caller may well
|
|
437
|
-
// be reusing or asserting on it
|
|
438
|
-
const clientConfig: MsalClientConfig = {
|
|
439
|
-
...declared,
|
|
440
|
-
auth: { ...declared.auth },
|
|
441
|
-
// Default to localStorage: MSAL supports sessionStorage too, but
|
|
442
|
-
// localStorage is the standard for persistent auth in browsers
|
|
443
|
-
cache: declared.cache ?? { cacheLocation: 'localStorage' },
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
// Auto-generate authority URL from tenant ID if not explicitly provided
|
|
447
|
-
// This simplifies configuration for most common cases
|
|
448
|
-
if (!clientConfig.auth.authority && clientConfig.auth.tenantId) {
|
|
449
|
-
clientConfig.auth.authority = `https://login.microsoftonline.com/${clientConfig.auth.tenantId}`;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// Integrate framework telemetry with MSAL logging system
|
|
453
|
-
// This allows MSAL events to flow through the framework's telemetry pipeline
|
|
454
|
-
if (!clientConfig.system?.loggerOptions && config.telemetry?.provider) {
|
|
455
|
-
const { provider, metadata, scope } = config.telemetry;
|
|
456
|
-
|
|
457
|
-
provider.trackEvent({
|
|
458
|
-
name: 'module-msal.configurator._processConfig.client-telemetry-connected',
|
|
459
|
-
level: TelemetryLevel.Debug,
|
|
460
|
-
scope,
|
|
461
|
-
metadata,
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
clientConfig.system = {
|
|
465
|
-
...clientConfig.system,
|
|
466
|
-
loggerOptions: {
|
|
467
|
-
// Only log PII in development to protect user privacy in production
|
|
468
|
-
piiLoggingEnabled: process.env.NODE_ENV === 'development',
|
|
469
|
-
// Bridge MSAL log events to framework telemetry system
|
|
470
|
-
loggerCallback: createClientLogCallback(provider, metadata, [...scope, '3rd-party']),
|
|
471
|
-
// Use Warning level by default - captures errors and warnings without being verbose
|
|
472
|
-
logLevel: LogLevel.Warning,
|
|
473
|
-
// Preserve any user-provided logger options (allows customization)
|
|
474
|
-
...clientConfig.system?.loggerOptions,
|
|
475
|
-
},
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Apply silent cache lookup policy if configured
|
|
480
|
-
if (config.cacheLookupPolicy !== undefined) {
|
|
481
|
-
clientConfig.cacheLookupPolicy = config.cacheLookupPolicy;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
return clientConfig;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AcquireTokenOptions,
|
|
3
|
-
AcquireTokenResult,
|
|
4
|
-
IMsalClient,
|
|
5
|
-
LoginOptions,
|
|
6
|
-
LoginResult,
|
|
7
|
-
LogoutOptions,
|
|
8
|
-
} from './MsalClient.interface';
|
|
9
|
-
|
|
10
|
-
import type { IProxyProvider } from './MsalProxyProvider.interface';
|
|
11
|
-
|
|
12
|
-
import type { AccountInfo, AuthenticationResult } from './types';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Legacy token acquisition options maintaining backward compatibility.
|
|
16
|
-
*
|
|
17
|
-
* This type extends `AcquireTokenOptions` with an optional `scopes` property
|
|
18
|
-
* to support legacy API calls that passed scopes directly rather than in the request object.
|
|
19
|
-
*
|
|
20
|
-
* @property scopes - Optional array of OAuth scopes (deprecated, use request.scopes)
|
|
21
|
-
*
|
|
22
|
-
* @deprecated Use the modern format with scopes in the request object instead
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* // Deprecated legacy format
|
|
26
|
-
* acquireToken({ scopes: ['User.Read'] })
|
|
27
|
-
*
|
|
28
|
-
* // Modern format (preferred)
|
|
29
|
-
* acquireToken({ request: { scopes: ['User.Read'] } })
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export type AcquireTokenOptionsLegacy = AcquireTokenOptions & { scopes?: string[] };
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Interface for MSAL v4 authentication provider.
|
|
36
|
-
*
|
|
37
|
-
* This interface defines the contract for authentication providers that work
|
|
38
|
-
* with Microsoft Authentication Library v4, providing a unified API for
|
|
39
|
-
* token acquisition, user authentication, and account management.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```typescript
|
|
43
|
-
* const provider: IMsalProvider = new MsalProvider(config);
|
|
44
|
-
*
|
|
45
|
-
* // Login user (v4 format)
|
|
46
|
-
* await provider.login({ request: { scopes: ['User.Read'] } });
|
|
47
|
-
*
|
|
48
|
-
* // Acquire token (v4 format - recommended)
|
|
49
|
-
* const token = await provider.acquireAccessToken({
|
|
50
|
-
* request: { scopes: ['https://graph.microsoft.com/.default'] }
|
|
51
|
-
* });
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
|
-
export interface IMsalProvider extends IProxyProvider {
|
|
55
|
-
/**
|
|
56
|
-
* The MSAL PublicClientApplication client instance.
|
|
57
|
-
*
|
|
58
|
-
* Provides access to the underlying MSAL client for advanced use cases.
|
|
59
|
-
* Use provider methods for standard authentication operations.
|
|
60
|
-
*/
|
|
61
|
-
readonly client: IMsalClient;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* The currently authenticated account information.
|
|
65
|
-
*
|
|
66
|
-
* Returns the active account if available, or null if no user is authenticated.
|
|
67
|
-
*/
|
|
68
|
-
readonly account: AccountInfo | null;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Initializes the MSAL provider and handles authentication state.
|
|
72
|
-
*
|
|
73
|
-
* This method must be called before using other provider methods. It:
|
|
74
|
-
* - Initializes the MSAL client
|
|
75
|
-
* - Processes any pending authentication redirects
|
|
76
|
-
* - Attempts automatic login if requiresAuth is enabled
|
|
77
|
-
*
|
|
78
|
-
* @returns Promise that resolves when initialization is complete
|
|
79
|
-
*/
|
|
80
|
-
initialize(): Promise<void>;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Acquires an access token string for the specified scopes.
|
|
84
|
-
*
|
|
85
|
-
* This is a convenience method that returns only the access token string,
|
|
86
|
-
* unlike `acquireToken` which returns the full authentication result.
|
|
87
|
-
*
|
|
88
|
-
* @param options - Token acquisition options including scopes
|
|
89
|
-
* @returns Promise resolving to the access token string, or undefined if acquisition fails
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* ```typescript
|
|
93
|
-
* const token = await provider.acquireAccessToken({
|
|
94
|
-
* request: { scopes: ['User.Read'] }
|
|
95
|
-
* });
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
98
|
-
acquireAccessToken(
|
|
99
|
-
options?: AcquireTokenOptions | AcquireTokenOptionsLegacy,
|
|
100
|
-
): Promise<string | undefined>;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Acquires a full authentication result including token and account information.
|
|
104
|
-
*
|
|
105
|
-
* This method attempts silent token acquisition first, then falls back to interactive
|
|
106
|
-
* authentication based on the configured behavior (popup or redirect).
|
|
107
|
-
*
|
|
108
|
-
* @param options - Token acquisition options including scopes
|
|
109
|
-
* @returns Promise resolving to full authentication result or null/undefined on failure
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* ```typescript
|
|
113
|
-
* const result = await provider.acquireToken({
|
|
114
|
-
* request: { scopes: ['User.Read'] },
|
|
115
|
-
* behavior: 'popup'
|
|
116
|
-
* });
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
acquireToken(
|
|
120
|
-
options?: AcquireTokenOptions | AcquireTokenOptionsLegacy,
|
|
121
|
-
): Promise<AcquireTokenResult>;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Authenticates a user interactively with Microsoft Identity Platform.
|
|
125
|
-
*
|
|
126
|
-
* This method implements a sophisticated flow that attempts silent authentication
|
|
127
|
-
* first (if configured) and falls back to interactive authentication based on behavior.
|
|
128
|
-
*
|
|
129
|
-
* @param options - Login configuration options including request, behavior, and silent flag
|
|
130
|
-
* @returns Promise resolving to authentication result or undefined for redirect flows
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* ```typescript
|
|
134
|
-
* // Basic login with default settings
|
|
135
|
-
* await provider.login({ request: { scopes: ['User.Read'] } });
|
|
136
|
-
* ```
|
|
137
|
-
*/
|
|
138
|
-
login(options: LoginOptions): Promise<LoginResult>;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Logs out the current user and clears authentication state.
|
|
142
|
-
*
|
|
143
|
-
* Initiates a logout flow that clears local tokens and navigates to Microsoft's
|
|
144
|
-
* logout endpoint. Always uses redirect flow for reliability.
|
|
145
|
-
*
|
|
146
|
-
* @param options - Optional logout configuration
|
|
147
|
-
* @returns Promise resolving to true on success, false on failure
|
|
148
|
-
*
|
|
149
|
-
* @example
|
|
150
|
-
* ```typescript
|
|
151
|
-
* // Basic logout
|
|
152
|
-
* await provider.logout();
|
|
153
|
-
*
|
|
154
|
-
* // Logout with redirect
|
|
155
|
-
* await provider.logout({ redirectUri: 'https://app.com/logout' });
|
|
156
|
-
* ```
|
|
157
|
-
*/
|
|
158
|
-
logout(options?: LogoutOptions): Promise<boolean>;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Processes any pending authentication redirect after browser navigation.
|
|
162
|
-
*
|
|
163
|
-
* This method must be called on app initialization to handle authentication
|
|
164
|
-
* results from redirect-based flows. It processes tokens and account information
|
|
165
|
-
* returned by Microsoft's identity provider.
|
|
166
|
-
*
|
|
167
|
-
* @returns Promise resolving to authentication result or null if no redirect pending
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```typescript
|
|
171
|
-
* // Call on app startup
|
|
172
|
-
* const result = await provider.handleRedirect();
|
|
173
|
-
* if (result?.account) {
|
|
174
|
-
* // User successfully authenticated via redirect
|
|
175
|
-
* }
|
|
176
|
-
* ```
|
|
177
|
-
*/
|
|
178
|
-
handleRedirect(): Promise<AuthenticationResult | null>;
|
|
179
|
-
}
|