@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
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
IPublicClientApplication,
|
|
3
|
-
AccountInfo,
|
|
4
|
-
AuthenticationResult,
|
|
5
|
-
PopupRequest,
|
|
6
|
-
RedirectRequest,
|
|
7
|
-
AuthorizationCodeRequest,
|
|
8
|
-
} from '@azure/msal-browser';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Authentication behavior type determining the interaction method.
|
|
12
|
-
*
|
|
13
|
-
* - 'popup': Opens authentication in a popup window (returns result immediately)
|
|
14
|
-
* - 'redirect': Navigates browser to authentication page (returns void, result via handleRedirectPromise)
|
|
15
|
-
*/
|
|
16
|
-
export type AuthBehavior = 'popup' | 'redirect';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Options for acquiring an access token.
|
|
20
|
-
*
|
|
21
|
-
* This type ensures either the legacy or modern approach is used by requiring
|
|
22
|
-
* the request parameter while allowing optional configuration for behavior and silent mode.
|
|
23
|
-
*
|
|
24
|
-
* @property request - MSAL request object for popup or redirect authentication
|
|
25
|
-
* @property behavior - Optional authentication method (popup or redirect). Defaults to 'redirect'
|
|
26
|
-
* @property silent - Optional flag to attempt silent token acquisition first. Defaults to true if account is available
|
|
27
|
-
*/
|
|
28
|
-
export type AcquireTokenOptions = {
|
|
29
|
-
request: PopupRequest | RedirectRequest;
|
|
30
|
-
behavior?: AuthBehavior;
|
|
31
|
-
silent?: boolean;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Result type for token acquisition operations.
|
|
36
|
-
*
|
|
37
|
-
* Returns the authentication result on success, or null/undefined on failure or redirect.
|
|
38
|
-
* For redirect flows, returns undefined (void) because browser navigation interrupts execution.
|
|
39
|
-
*/
|
|
40
|
-
export type AcquireTokenResult = AuthenticationResult | null | undefined;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Options for user login/authentication.
|
|
44
|
-
*
|
|
45
|
-
* @property request - MSAL request object for popup or redirect authentication
|
|
46
|
-
* @property behavior - Optional authentication method (popup or redirect). Defaults to 'redirect'
|
|
47
|
-
* @property silent - Optional flag to attempt silent SSO authentication first. Defaults to true
|
|
48
|
-
*/
|
|
49
|
-
export type LoginOptions = {
|
|
50
|
-
request: PopupRequest | RedirectRequest;
|
|
51
|
-
behavior?: AuthBehavior;
|
|
52
|
-
silent?: boolean;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Options for user logout.
|
|
57
|
-
*
|
|
58
|
-
* @property redirectUri - Optional URI to redirect to after logout completes
|
|
59
|
-
* @property account - Optional account to log out (defaults to active account if not provided)
|
|
60
|
-
*/
|
|
61
|
-
export type LogoutOptions = {
|
|
62
|
-
redirectUri?: string;
|
|
63
|
-
account?: AccountInfo;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Result type for login operations.
|
|
68
|
-
*
|
|
69
|
-
* Returns the authentication result on success, or undefined on redirect-based flows
|
|
70
|
-
* (where the browser navigates away). For redirect flows, result is available via handleRedirectPromise.
|
|
71
|
-
*/
|
|
72
|
-
export type LoginResult = AuthenticationResult | undefined;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Interface for MSAL v4 client with additional properties and methods.
|
|
76
|
-
*
|
|
77
|
-
* This interface extends the standard MSAL v4 PublicClientApplication
|
|
78
|
-
* with additional properties and methods needed for the framework.
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```typescript
|
|
82
|
-
* const client: IMsalClient = new MsalClient(config);
|
|
83
|
-
*
|
|
84
|
-
* // Access additional properties
|
|
85
|
-
* const tenantId = client.tenantId;
|
|
86
|
-
* const hasValidClaims = client.hasValidClaims;
|
|
87
|
-
*
|
|
88
|
-
* // Use enhanced methods
|
|
89
|
-
* const result = await client.login({ request: { scopes: ['User.Read'] } });
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
export interface IMsalClient extends IPublicClientApplication {
|
|
93
|
-
/** Configured client ID */
|
|
94
|
-
clientId: string | undefined;
|
|
95
|
-
|
|
96
|
-
/** Tenant ID for the client domain */
|
|
97
|
-
tenantId: string | undefined;
|
|
98
|
-
|
|
99
|
-
/** Check if the current account has valid claims */
|
|
100
|
-
hasValidClaims: boolean;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Login user with enhanced options
|
|
104
|
-
* @param options - Login configuration options
|
|
105
|
-
* @returns Promise resolving to authentication result or undefined
|
|
106
|
-
*/
|
|
107
|
-
login(options: LoginOptions): Promise<LoginResult>;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Logout user with enhanced options
|
|
111
|
-
* @param options - Logout configuration options
|
|
112
|
-
* @returns Promise resolving to void
|
|
113
|
-
*/
|
|
114
|
-
logout(options: LogoutOptions): Promise<void>;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Acquire access token with enhanced options
|
|
118
|
-
* @param options - Token acquisition configuration options
|
|
119
|
-
* @returns Promise resolving to authentication result or null/undefined
|
|
120
|
-
*/
|
|
121
|
-
acquireToken(options: AcquireTokenOptions): Promise<AcquireTokenResult>;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Exchange a backend-issued authorization code for tokens (SPA Auth Code Flow).
|
|
125
|
-
*
|
|
126
|
-
* This method enables automatic sign-in using a backend-issued auth code without
|
|
127
|
-
* requiring interactive MSAL flows. Primarily used during module initialization.
|
|
128
|
-
*
|
|
129
|
-
* @param request - Authorization code request with code and scopes
|
|
130
|
-
* @returns Promise resolving to authentication result with tokens
|
|
131
|
-
*
|
|
132
|
-
* @remarks
|
|
133
|
-
* - Auth codes are single-use and short-lived (typically 5-10 minutes)
|
|
134
|
-
* - MSAL handles token validation, caching, and refresh token management
|
|
135
|
-
* - Follows Microsoft's standard SPA Auth Code Flow pattern
|
|
136
|
-
* - Inherited from PublicClientApplication (MSAL Browser v4+)
|
|
137
|
-
*/
|
|
138
|
-
acquireTokenByCode(request: AuthorizationCodeRequest): Promise<AuthenticationResult>;
|
|
139
|
-
}
|
package/src/MsalClient.ts
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PublicClientApplication,
|
|
3
|
-
type CacheLookupPolicy,
|
|
4
|
-
type SilentRequest,
|
|
5
|
-
type Configuration,
|
|
6
|
-
type EndSessionRequest,
|
|
7
|
-
type PopupRequest,
|
|
8
|
-
type RedirectRequest,
|
|
9
|
-
} from '@azure/msal-browser';
|
|
10
|
-
|
|
11
|
-
import type {
|
|
12
|
-
IMsalClient,
|
|
13
|
-
AcquireTokenResult,
|
|
14
|
-
LoginOptions,
|
|
15
|
-
LogoutOptions,
|
|
16
|
-
LoginResult,
|
|
17
|
-
AcquireTokenOptions,
|
|
18
|
-
} from './MsalClient.interface';
|
|
19
|
-
|
|
20
|
-
export type { IMsalClient };
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Fallback correlation ID for logger calls when request doesn't provide one.
|
|
24
|
-
* Empty string indicates a non-request-specific log (validation, configuration warnings).
|
|
25
|
-
*/
|
|
26
|
-
const FUSION_CORRELATION_ID = '';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* MSAL client configuration extending the standard MSAL Configuration.
|
|
30
|
-
*
|
|
31
|
-
* This type adds tenant-specific configuration options while maintaining
|
|
32
|
-
* full compatibility with the base MSAL Configuration type.
|
|
33
|
-
*
|
|
34
|
-
* @remarks
|
|
35
|
-
* The `tenantId` in the auth configuration is optional but recommended for
|
|
36
|
-
* multi-tenant applications. When provided, it's used for better tenant isolation
|
|
37
|
-
* and can be accessed via the client's `tenantId` property.
|
|
38
|
-
*/
|
|
39
|
-
export type MsalClientConfig = Configuration & {
|
|
40
|
-
auth: {
|
|
41
|
-
/** Optional tenant identifier for Azure AD tenant */
|
|
42
|
-
tenantId?: string;
|
|
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;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* MSAL v4 client implementation with extended properties and methods.
|
|
65
|
-
*
|
|
66
|
-
* This class extends the standard MSAL PublicClientApplication to provide
|
|
67
|
-
* additional properties (tenantId, clientId, hasValidClaims) and enhanced
|
|
68
|
-
* authentication methods with better options for behavior and silent flows.
|
|
69
|
-
*
|
|
70
|
-
* @example
|
|
71
|
-
* ```typescript
|
|
72
|
-
* const config: MsalClientConfig = {
|
|
73
|
-
* auth: {
|
|
74
|
-
* clientId: 'your-client-id',
|
|
75
|
-
* authority: 'https://login.microsoftonline.com/your-tenant-id',
|
|
76
|
-
* tenantId: 'your-tenant-id'
|
|
77
|
-
* }
|
|
78
|
-
* };
|
|
79
|
-
* const client = new MsalClient(config);
|
|
80
|
-
* await client.initialize();
|
|
81
|
-
* ```
|
|
82
|
-
*/
|
|
83
|
-
export class MsalClient extends PublicClientApplication implements IMsalClient {
|
|
84
|
-
#tenantId?: string;
|
|
85
|
-
#clientId?: string;
|
|
86
|
-
#cacheLookupPolicy?: CacheLookupPolicy;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Creates a new MSAL client instance.
|
|
90
|
-
*
|
|
91
|
-
* @param config - MSAL client configuration including auth settings
|
|
92
|
-
*/
|
|
93
|
-
constructor(config: MsalClientConfig) {
|
|
94
|
-
super(config);
|
|
95
|
-
this.#tenantId = config.auth?.tenantId;
|
|
96
|
-
this.#clientId = config.auth?.clientId;
|
|
97
|
-
this.#cacheLookupPolicy = config.cacheLookupPolicy;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Tenant identifier for the configured Azure AD tenant.
|
|
102
|
-
*
|
|
103
|
-
* @returns The tenant ID string if configured, undefined otherwise
|
|
104
|
-
*/
|
|
105
|
-
get tenantId(): string | undefined {
|
|
106
|
-
return this.#tenantId;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Client identifier (application ID) for the configured Azure AD application.
|
|
111
|
-
*
|
|
112
|
-
* @returns The client ID string if configured, undefined otherwise
|
|
113
|
-
*/
|
|
114
|
-
get clientId(): string | undefined {
|
|
115
|
-
return this.#clientId;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Checks if the currently active account has valid ID token claims.
|
|
120
|
-
*
|
|
121
|
-
* This property validates that the ID token's expiration claim (exp) is in the future,
|
|
122
|
-
* indicating the account is still authenticated and the session is valid.
|
|
123
|
-
*
|
|
124
|
-
* @returns True if the account has unexpired token claims, false otherwise
|
|
125
|
-
*/
|
|
126
|
-
get hasValidClaims(): boolean {
|
|
127
|
-
const idTokenClaims = this.getActiveAccount()?.idTokenClaims;
|
|
128
|
-
// Compare token expiration time (seconds since epoch) with current time
|
|
129
|
-
return Number(idTokenClaims?.exp) > Number(Math.ceil(Date.now() / 1000));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Authenticates user with support for silent SSO, popup, and redirect flows.
|
|
134
|
-
*
|
|
135
|
-
* @param options - Login configuration with request, behavior, and silent flag
|
|
136
|
-
* @returns Promise resolving to authentication result
|
|
137
|
-
*
|
|
138
|
-
* @remarks
|
|
139
|
-
* Authentication flow priority:
|
|
140
|
-
* 1. Silent SSO (if enabled and account/loginHint provided)
|
|
141
|
-
* 2. Interactive method based on behavior (popup or redirect)
|
|
142
|
-
*
|
|
143
|
-
* **Behavior differences:**
|
|
144
|
-
* - **Popup**: Opens authentication popup window and returns authentication result immediately
|
|
145
|
-
* - **Redirect**: Navigates browser to Microsoft login page. Returns `void` because the browser
|
|
146
|
-
* navigates to a new page. After redirect completes, the result will be available via
|
|
147
|
-
* `handleRedirectPromise()` when the app loads on the new page.
|
|
148
|
-
*
|
|
149
|
-
* @throws {Error} If an invalid `options.behavior` value is provided.
|
|
150
|
-
*/
|
|
151
|
-
async login(options: Required<LoginOptions>): Promise<LoginResult> {
|
|
152
|
-
// Attempt silent authentication first if enabled
|
|
153
|
-
// This provides better UX by avoiding unnecessary popups/redirects
|
|
154
|
-
if (options.silent) {
|
|
155
|
-
// Warn early when neither an account nor login hint is available for silent SSO
|
|
156
|
-
if (!options.request.account && !options.request.loginHint) {
|
|
157
|
-
this.getLogger().warning(
|
|
158
|
-
'No account or login hint provided, please provide an account or login hint in the request',
|
|
159
|
-
options.request.correlationId || FUSION_CORRELATION_ID,
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
try {
|
|
163
|
-
return await this.ssoSilent(options.request as SilentRequest);
|
|
164
|
-
} catch {
|
|
165
|
-
// Silent login failed - continue to interactive flow
|
|
166
|
-
this.getLogger().warning(
|
|
167
|
-
'Silent login failed, falling back to interactive',
|
|
168
|
-
options.request.correlationId || FUSION_CORRELATION_ID,
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Perform interactive authentication based on specified behavior
|
|
174
|
-
switch (options.behavior) {
|
|
175
|
-
case 'popup':
|
|
176
|
-
// Popup flow - returns result immediately after user completes authentication
|
|
177
|
-
return await this.loginPopup(options.request as PopupRequest);
|
|
178
|
-
case 'redirect':
|
|
179
|
-
// Redirect flow - browser navigates to Microsoft login page
|
|
180
|
-
// Returns void because browser navigation interrupts execution on current page
|
|
181
|
-
// Result will be available via handleRedirectPromise() after app loads on new page
|
|
182
|
-
await this.loginRedirect(options.request as RedirectRequest);
|
|
183
|
-
break;
|
|
184
|
-
default:
|
|
185
|
-
throw new Error(
|
|
186
|
-
`Invalid behavior provided: ${options.behavior}, please provide a valid behavior, see options.behavior for more information.`,
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Logs out the current user and clears authentication state.
|
|
193
|
-
*
|
|
194
|
-
* This method initiates a logout flow using the redirect mechanism, which navigates
|
|
195
|
-
* the user to the Microsoft logout endpoint to clear session cookies and tokens.
|
|
196
|
-
*
|
|
197
|
-
* @param options - Logout configuration options
|
|
198
|
-
* @param options.account - Account to log out (defaults to active account if not provided)
|
|
199
|
-
* @param options.redirectUri - URI to redirect to after logout completes
|
|
200
|
-
* @returns Promise that resolves when logout redirect is initiated
|
|
201
|
-
*
|
|
202
|
-
* @remarks
|
|
203
|
-
* - This method always uses redirect flow for logout (more reliable than popup)
|
|
204
|
-
* - **Returns `void`**: The browser navigates to Microsoft's logout page, which interrupts
|
|
205
|
-
* execution on the current page. This is expected behavior for redirect-based logout.
|
|
206
|
-
* - If no account is provided, uses the currently active account
|
|
207
|
-
* - After redirect, user will be logged out at Microsoft's identity provider
|
|
208
|
-
* - Application state and local tokens are cleared during this process
|
|
209
|
-
*
|
|
210
|
-
* @example
|
|
211
|
-
* ```typescript
|
|
212
|
-
* // Basic logout with active account
|
|
213
|
-
* await client.logout();
|
|
214
|
-
*
|
|
215
|
-
* // Logout with custom redirect URI
|
|
216
|
-
* await client.logout({
|
|
217
|
-
* redirectUri: 'https://app.com/logged-out'
|
|
218
|
-
* });
|
|
219
|
-
* ```
|
|
220
|
-
*/
|
|
221
|
-
async logout(options?: LogoutOptions): Promise<void> {
|
|
222
|
-
// Warn when no account was supplied since the active account will be used instead
|
|
223
|
-
if (!options?.account) {
|
|
224
|
-
this.getLogger().warning(
|
|
225
|
-
'No account available for logout, please provide an account in the options',
|
|
226
|
-
FUSION_CORRELATION_ID,
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const logoutRequest: EndSessionRequest = {
|
|
231
|
-
account: options?.account,
|
|
232
|
-
postLogoutRedirectUri: options?.redirectUri,
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// Browser will navigate to Microsoft logout page
|
|
236
|
-
// Returns void because navigation interrupts execution on current page
|
|
237
|
-
await this.logoutRedirect(logoutRequest);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Acquires an access token with smart silent/interactive fallback.
|
|
242
|
-
*
|
|
243
|
-
* @param options - Token acquisition configuration
|
|
244
|
-
* @returns Promise resolving to authentication result or null/undefined
|
|
245
|
-
*
|
|
246
|
-
* @remarks
|
|
247
|
-
* Token acquisition flow:
|
|
248
|
-
* 1. If silent=true and account available, attempt silent token acquisition from cache
|
|
249
|
-
* 2. On silent failure (or not attempted), use interactive method based on behavior
|
|
250
|
-
* 3. Interactive method based on behavior (popup or redirect)
|
|
251
|
-
*
|
|
252
|
-
* **Behavior differences:**
|
|
253
|
-
* - **Popup**: Opens authentication popup window and returns token result immediately
|
|
254
|
-
* - **Redirect**: Navigates browser to Microsoft login page. Returns `void` because the browser
|
|
255
|
-
* navigates to a new page. After redirect completes, handle the result via
|
|
256
|
-
* `handleRedirectPromise()` when the app loads on the new page.
|
|
257
|
-
*
|
|
258
|
-
* The default silent behavior is determined by presence of account in the request.
|
|
259
|
-
* This provides optimal UX by minimizing unnecessary user interactions.
|
|
260
|
-
*
|
|
261
|
-
* @throws {Error} If no `request` is provided in `options`.
|
|
262
|
-
*/
|
|
263
|
-
async acquireToken(options: AcquireTokenOptions): Promise<AcquireTokenResult> {
|
|
264
|
-
const { behavior = 'redirect', silent = !!options.request?.account, request } = options;
|
|
265
|
-
|
|
266
|
-
// A request is required to know which scopes/account to acquire a token for
|
|
267
|
-
if (!request) {
|
|
268
|
-
throw new Error('No request provided, please provide a request in the options');
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Warn when no scopes are requested, since MSAL requires at least one scope
|
|
272
|
-
if (request.scopes.length === 0) {
|
|
273
|
-
this.getLogger().warning(
|
|
274
|
-
'No scopes provided, please provide scopes in the request option, see options.request for more information.',
|
|
275
|
-
request.correlationId || FUSION_CORRELATION_ID,
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Attempt silent token acquisition first
|
|
280
|
-
// This fetches from cache or uses refresh token without user interaction
|
|
281
|
-
if (silent) {
|
|
282
|
-
// Only silent-acquire when an account is available to look up cached tokens for
|
|
283
|
-
if (request.account) {
|
|
284
|
-
try {
|
|
285
|
-
this.getLogger().verbose(
|
|
286
|
-
'Attempting to acquire token silently',
|
|
287
|
-
request.correlationId || FUSION_CORRELATION_ID,
|
|
288
|
-
);
|
|
289
|
-
return await this.acquireTokenSilent({
|
|
290
|
-
// Instance-level policy is the default; request-level cacheLookupPolicy takes precedence
|
|
291
|
-
cacheLookupPolicy: this.#cacheLookupPolicy,
|
|
292
|
-
...(request as SilentRequest),
|
|
293
|
-
});
|
|
294
|
-
} catch {
|
|
295
|
-
// Silent acquisition failed - fall back to interactive
|
|
296
|
-
this.getLogger().warning(
|
|
297
|
-
'Silent token acquisition failed, falling back to interactive',
|
|
298
|
-
request.correlationId || FUSION_CORRELATION_ID,
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
} else {
|
|
302
|
-
this.getLogger().warning(
|
|
303
|
-
'Cannot acquire token silently, no account provided, falling back to interactive.',
|
|
304
|
-
request.correlationId || FUSION_CORRELATION_ID,
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Perform interactive token acquisition
|
|
310
|
-
switch (behavior) {
|
|
311
|
-
case 'popup':
|
|
312
|
-
// Popup flow - returns token immediately after user grants permission
|
|
313
|
-
return await this.acquireTokenPopup(request);
|
|
314
|
-
case 'redirect':
|
|
315
|
-
// Redirect flow - browser navigates to Microsoft login page
|
|
316
|
-
// Returns void because browser navigation interrupts execution on current page
|
|
317
|
-
// Token will be available via handleRedirectPromise() after app loads on new page
|
|
318
|
-
await this.acquireTokenRedirect(request);
|
|
319
|
-
break;
|
|
320
|
-
default:
|
|
321
|
-
throw new Error(
|
|
322
|
-
`Invalid behavior provided: ${behavior}, please provide a valid behavior, see options.behavior for more information.`,
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|