@azure/msal-angular 4.0.20 → 5.0.0-alpha.0

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.
Files changed (37) hide show
  1. package/IMsalService.d.ts +16 -17
  2. package/README.md +3 -1
  3. package/constants.d.ts +9 -5
  4. package/{fesm2020 → fesm2022}/azure-msal-angular.mjs +740 -734
  5. package/fesm2022/azure-msal-angular.mjs.map +1 -0
  6. package/index.d.ts +5 -5
  7. package/msal.broadcast.config.d.ts +3 -3
  8. package/msal.broadcast.service.d.ts +19 -19
  9. package/msal.guard.config.d.ts +9 -9
  10. package/msal.guard.d.ts +43 -43
  11. package/msal.interceptor.config.d.ts +13 -13
  12. package/msal.interceptor.d.ts +70 -70
  13. package/msal.module.d.ts +13 -13
  14. package/msal.navigation.client.d.ts +19 -19
  15. package/msal.redirect.component.d.ts +15 -15
  16. package/msal.service.d.ts +32 -33
  17. package/package.json +5 -15
  18. package/packageMetadata.d.ts +2 -2
  19. package/public-api.d.ts +17 -17
  20. package/esm2020/IMsalService.mjs +0 -6
  21. package/esm2020/azure-msal-angular.mjs +0 -5
  22. package/esm2020/constants.mjs +0 -10
  23. package/esm2020/msal.broadcast.config.mjs +0 -6
  24. package/esm2020/msal.broadcast.service.mjs +0 -66
  25. package/esm2020/msal.guard.config.mjs +0 -6
  26. package/esm2020/msal.guard.mjs +0 -218
  27. package/esm2020/msal.interceptor.config.mjs +0 -6
  28. package/esm2020/msal.interceptor.mjs +0 -270
  29. package/esm2020/msal.module.mjs +0 -46
  30. package/esm2020/msal.navigation.client.mjs +0 -53
  31. package/esm2020/msal.redirect.component.mjs +0 -31
  32. package/esm2020/msal.service.mjs +0 -88
  33. package/esm2020/packageMetadata.mjs +0 -4
  34. package/esm2020/public-api.mjs +0 -18
  35. package/fesm2015/azure-msal-angular.mjs +0 -762
  36. package/fesm2015/azure-msal-angular.mjs.map +0 -1
  37. package/fesm2020/azure-msal-angular.mjs.map +0 -1
@@ -1,757 +1,763 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Inject, Optional, Component, NgModule } from '@angular/core';
3
- import { InteractionStatus, EventMessageUtils, WrapperSKU, InteractionType, BrowserConfigurationAuthError, UrlString, BrowserUtils, StringUtils, NavigationClient } from '@azure/msal-browser';
2
+ import { InjectionToken, Inject, Optional, Injectable, Component, NgModule } from '@angular/core';
3
+ import { InteractionStatus, EventMessageUtils, WrapperSKU, InteractionType, BrowserConfigurationAuthError, BrowserUtils, StringUtils, NavigationClient, UrlString } from '@azure/msal-browser';
4
4
  import { ReplaySubject, Subject, BehaviorSubject, from, of, EMPTY } from 'rxjs';
5
5
  import * as i3 from '@angular/common';
6
6
  import { DOCUMENT, CommonModule } from '@angular/common';
7
7
  import { map, concatMap, catchError, switchMap, take, filter } from 'rxjs/operators';
8
8
  import * as i4 from '@angular/router';
9
9
 
10
- /* eslint-disable header/header */
11
- const name = "@azure/msal-angular";
12
- const version = "4.0.20";
10
+ /* eslint-disable header/header */
11
+ const name = "@azure/msal-angular";
12
+ const version = "5.0.0-alpha.0";
13
13
 
14
- /*
15
- * Copyright (c) Microsoft Corporation. All rights reserved.
16
- * Licensed under the MIT License.
17
- */
18
- const MSAL_INSTANCE = new InjectionToken("MSAL_INSTANCE");
19
- const MSAL_GUARD_CONFIG = new InjectionToken("MSAL_GUARD_CONFIG");
20
- const MSAL_INTERCEPTOR_CONFIG = new InjectionToken("MSAL_INTERCEPTOR_CONFIG");
14
+ /*
15
+ * Copyright (c) Microsoft Corporation. All rights reserved.
16
+ * Licensed under the MIT License.
17
+ */
18
+ const MSAL_INSTANCE = new InjectionToken("MSAL_INSTANCE");
19
+ const MSAL_GUARD_CONFIG = new InjectionToken("MSAL_GUARD_CONFIG");
20
+ const MSAL_INTERCEPTOR_CONFIG = new InjectionToken("MSAL_INTERCEPTOR_CONFIG");
21
21
  const MSAL_BROADCAST_CONFIG = new InjectionToken("MSAL_BROADCAST_CONFIG");
22
22
 
23
- /*
24
- * Copyright (c) Microsoft Corporation. All rights reserved.
25
- * Licensed under the MIT License.
26
- */
27
- class MsalBroadcastService {
28
- constructor(msalInstance, msalBroadcastConfig) {
29
- this.msalInstance = msalInstance;
30
- this.msalBroadcastConfig = msalBroadcastConfig;
31
- // Make _msalSubject a ReplaySubject if configured to replay past events
32
- if (this.msalBroadcastConfig &&
33
- this.msalBroadcastConfig.eventsToReplay > 0) {
34
- this.msalInstance
35
- .getLogger()
36
- .clone(name, version)
37
- .verbose(`BroadcastService - eventsToReplay set on BroadcastConfig, replaying the last ${this.msalBroadcastConfig.eventsToReplay} events`);
38
- this._msalSubject = new ReplaySubject(this.msalBroadcastConfig.eventsToReplay);
39
- }
40
- else {
41
- // Defaults to _msalSubject being a Subject
42
- this._msalSubject = new Subject();
43
- }
44
- this.msalSubject$ = this._msalSubject.asObservable();
45
- // InProgress as BehaviorSubject so most recent inProgress state will be available upon subscription
46
- this._inProgress = new BehaviorSubject(InteractionStatus.Startup);
47
- this.inProgress$ = this._inProgress.asObservable();
48
- this.msalInstance.addEventCallback((message) => {
49
- this._msalSubject.next(message);
50
- const status = EventMessageUtils.getInteractionStatusFromEvent(message, this._inProgress.value);
51
- if (status !== null) {
52
- this.msalInstance
53
- .getLogger()
54
- .clone(name, version)
55
- .verbose(`BroadcastService - ${message.eventType} results in setting inProgress from ${this._inProgress.value} to ${status}`);
56
- this._inProgress.next(status);
57
- }
58
- });
59
- }
60
- /**
61
- * Resets inProgress state to None
62
- */
63
- resetInProgressEvent() {
64
- if (this._inProgress.value === InteractionStatus.Startup) {
65
- this._inProgress.next(InteractionStatus.None);
66
- }
67
- }
68
- }
69
- MsalBroadcastServicefac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService, deps: [{ token: MSAL_INSTANCE }, { token: MSAL_BROADCAST_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
70
- MsalBroadcastService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService });
71
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalBroadcastService, decorators: [{
72
- type: Injectable
73
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
74
- type: Inject,
75
- args: [MSAL_INSTANCE]
76
- }] }, { type: undefined, decorators: [{
77
- type: Optional
78
- }, {
79
- type: Inject,
80
- args: [MSAL_BROADCAST_CONFIG]
81
- }] }]; } });
23
+ /*
24
+ * Copyright (c) Microsoft Corporation. All rights reserved.
25
+ * Licensed under the MIT License.
26
+ */
27
+ class MsalBroadcastService {
28
+ constructor(msalInstance, msalBroadcastConfig) {
29
+ this.msalInstance = msalInstance;
30
+ this.msalBroadcastConfig = msalBroadcastConfig;
31
+ // Make _msalSubject a ReplaySubject if configured to replay past events
32
+ if (this.msalBroadcastConfig &&
33
+ this.msalBroadcastConfig.eventsToReplay > 0) {
34
+ this.msalInstance
35
+ .getLogger()
36
+ .clone(name, version)
37
+ .verbose(`BroadcastService - eventsToReplay set on BroadcastConfig, replaying the last ${this.msalBroadcastConfig.eventsToReplay} events`, "");
38
+ this._msalSubject = new ReplaySubject(this.msalBroadcastConfig.eventsToReplay);
39
+ }
40
+ else {
41
+ // Defaults to _msalSubject being a Subject
42
+ this._msalSubject = new Subject();
43
+ }
44
+ this.msalSubject$ = this._msalSubject.asObservable();
45
+ // InProgress as BehaviorSubject so most recent inProgress state will be available upon subscription
46
+ this._inProgress = new BehaviorSubject(InteractionStatus.Startup);
47
+ this.inProgress$ = this._inProgress.asObservable();
48
+ this.msalInstance.addEventCallback((message) => {
49
+ this._msalSubject.next(message);
50
+ const status = EventMessageUtils.getInteractionStatusFromEvent(message, this._inProgress.value);
51
+ if (status !== null) {
52
+ this.msalInstance
53
+ .getLogger()
54
+ .clone(name, version)
55
+ .verbose(`BroadcastService - ${message.eventType} results in setting inProgress from ${this._inProgress.value} to ${status}`, "");
56
+ this._inProgress.next(status);
57
+ }
58
+ });
59
+ }
60
+ /**
61
+ * Resets inProgress state to None
62
+ */
63
+ resetInProgressEvent() {
64
+ if (this._inProgress.value === InteractionStatus.Startup) {
65
+ this._inProgress.next(InteractionStatus.None);
66
+ }
67
+ }
68
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalBroadcastService, deps: [{ token: MSAL_INSTANCE }, { token: MSAL_BROADCAST_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
69
+ static { thisprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalBroadcastService }); }
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalBroadcastService, decorators: [{
72
+ type: Injectable
73
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
74
+ type: Inject,
75
+ args: [MSAL_INSTANCE]
76
+ }] }, { type: undefined, decorators: [{
77
+ type: Optional
78
+ }, {
79
+ type: Inject,
80
+ args: [MSAL_BROADCAST_CONFIG]
81
+ }] }] });
82
82
 
83
- /*
84
- * Copyright (c) Microsoft Corporation. All rights reserved.
85
- * Licensed under the MIT License.
86
- */
87
- class MsalService {
88
- constructor(instance, location, injector) {
89
- this.instance = instance;
90
- this.location = location;
91
- this.injector = injector;
92
- const hash = this.location.path(true).split("#").pop();
93
- if (hash) {
94
- this.redirectHash = `#${hash}`;
95
- }
96
- this.instance.initializeWrapperLibrary(WrapperSKU.Angular, version);
97
- }
98
- initialize() {
99
- return from(this.instance.initialize());
100
- }
101
- acquireTokenPopup(request) {
102
- return from(this.instance.acquireTokenPopup(request));
103
- }
104
- acquireTokenRedirect(request) {
105
- return from(this.instance.acquireTokenRedirect(request));
106
- }
107
- acquireTokenSilent(silentRequest) {
108
- return from(this.instance.acquireTokenSilent(silentRequest));
109
- }
110
- handleRedirectObservable(hash) {
111
- return from(this.instance
112
- .initialize()
113
- .then(() => this.instance.handleRedirectPromise(hash || this.redirectHash))
114
- .finally(() => {
115
- // update inProgress state to none
116
- this.injector.get(MsalBroadcastService).resetInProgressEvent();
117
- }));
118
- }
119
- loginPopup(request) {
120
- return from(this.instance.loginPopup(request));
121
- }
122
- loginRedirect(request) {
123
- return from(this.instance.loginRedirect(request));
124
- }
125
- // @deprecated: Use logoutRedirect or logoutPopup
126
- logout(logoutRequest) {
127
- return from(this.instance.logout(logoutRequest));
128
- }
129
- logoutRedirect(logoutRequest) {
130
- return from(this.instance.logoutRedirect(logoutRequest));
131
- }
132
- logoutPopup(logoutRequest) {
133
- return from(this.instance.logoutPopup(logoutRequest));
134
- }
135
- ssoSilent(request) {
136
- return from(this.instance.ssoSilent(request));
137
- }
138
- /**
139
- * Gets logger for msal-angular.
140
- * If no logger set, returns logger instance created with same options as msal-browser
141
- */
142
- getLogger() {
143
- if (!this.logger) {
144
- this.logger = this.instance.getLogger().clone(name, version);
145
- }
146
- return this.logger;
147
- }
148
- // Create a logger instance for msal-angular with the same options as msal-browser
149
- setLogger(logger) {
150
- this.logger = logger.clone(name, version);
151
- this.instance.setLogger(logger);
152
- }
153
- }
154
- MsalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService, deps: [{ token: MSAL_INSTANCE }, { token: i3.Location }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
155
- MsalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService });
156
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalService, decorators: [{
157
- type: Injectable
158
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
159
- type: Inject,
160
- args: [MSAL_INSTANCE]
161
- }] }, { type: i3.Location }, { type: i0.Injector }]; } });
83
+ /*
84
+ * Copyright (c) Microsoft Corporation. All rights reserved.
85
+ * Licensed under the MIT License.
86
+ */
87
+ class MsalService {
88
+ constructor(instance, location, injector) {
89
+ this.instance = instance;
90
+ this.location = location;
91
+ this.injector = injector;
92
+ const hash = this.location.path(true).split("#").pop();
93
+ if (hash) {
94
+ this.redirectHash = `#${hash}`;
95
+ }
96
+ this.instance.initializeWrapperLibrary(WrapperSKU.Angular, version);
97
+ }
98
+ initialize() {
99
+ return from(this.instance.initialize());
100
+ }
101
+ acquireTokenPopup(request) {
102
+ return from(this.instance.acquireTokenPopup(request));
103
+ }
104
+ acquireTokenRedirect(request) {
105
+ return from(this.instance.acquireTokenRedirect(request));
106
+ }
107
+ acquireTokenSilent(silentRequest) {
108
+ return from(this.instance.acquireTokenSilent(silentRequest));
109
+ }
110
+ handleRedirectObservable(hash) {
111
+ return from(this.instance
112
+ .initialize()
113
+ .then(() => this.instance.handleRedirectPromise({
114
+ hash: hash || this.redirectHash,
115
+ }))
116
+ .finally(() => {
117
+ // update inProgress state to none
118
+ this.injector.get(MsalBroadcastService).resetInProgressEvent();
119
+ }));
120
+ }
121
+ loginPopup(request) {
122
+ return from(this.instance.loginPopup(request));
123
+ }
124
+ loginRedirect(request) {
125
+ return from(this.instance.loginRedirect(request));
126
+ }
127
+ logoutRedirect(logoutRequest) {
128
+ return from(this.instance.logoutRedirect(logoutRequest));
129
+ }
130
+ logoutPopup(logoutRequest) {
131
+ return from(this.instance.logoutPopup(logoutRequest));
132
+ }
133
+ ssoSilent(request) {
134
+ return from(this.instance.ssoSilent(request));
135
+ }
136
+ /**
137
+ * Gets logger for msal-angular.
138
+ * If no logger set, returns logger instance created with same options as msal-browser
139
+ */
140
+ getLogger() {
141
+ if (!this.logger) {
142
+ this.logger = this.instance.getLogger().clone(name, version);
143
+ }
144
+ return this.logger;
145
+ }
146
+ // Create a logger instance for msal-angular with the same options as msal-browser
147
+ setLogger(logger) {
148
+ this.logger = logger.clone(name, version);
149
+ this.instance.setLogger(logger);
150
+ }
151
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalService, deps: [{ token: MSAL_INSTANCE }, { token: i3.Location }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
152
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalService }); }
153
+ }
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalService, decorators: [{
155
+ type: Injectable
156
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
157
+ type: Inject,
158
+ args: [MSAL_INSTANCE]
159
+ }] }, { type: i3.Location }, { type: i0.Injector }] });
162
160
 
163
- /*
164
- * Copyright (c) Microsoft Corporation. All rights reserved.
165
- * Licensed under the MIT License.
166
- */
167
- class MsalGuard {
168
- constructor(msalGuardConfig, msalBroadcastService, authService, location, router) {
169
- this.msalGuardConfig = msalGuardConfig;
170
- this.msalBroadcastService = msalBroadcastService;
171
- this.authService = authService;
172
- this.location = location;
173
- this.router = router;
174
- // Subscribing so events in MsalGuard will set inProgress$ observable
175
- this.msalBroadcastService.inProgress$.subscribe();
176
- }
177
- /**
178
- * Parses url string to UrlTree
179
- * @param url
180
- */
181
- parseUrl(url) {
182
- return this.router.parseUrl(url);
183
- }
184
- /**
185
- * Builds the absolute url for the destination page
186
- * @param path Relative path of requested page
187
- * @returns Full destination url
188
- */
189
- getDestinationUrl(path) {
190
- this.authService.getLogger().verbose("Guard - getting destination url");
191
- // Absolute base url for the application (default to origin if base element not present)
192
- const baseElements = document.getElementsByTagName("base");
193
- const baseUrl = this.location.normalize(baseElements.length ? baseElements[0].href : window.location.origin);
194
- // Path of page (including hash, if using hash routing)
195
- const pathUrl = this.location.prepareExternalUrl(path);
196
- // Hash location strategy
197
- if (pathUrl.startsWith("#")) {
198
- this.authService
199
- .getLogger()
200
- .verbose("Guard - destination by hash routing");
201
- return `${baseUrl}/${pathUrl}`;
202
- }
203
- /*
204
- * If using path location strategy, pathUrl will include the relative portion of the base path (e.g. /base/page).
205
- * Since baseUrl also includes /base, can just concatentate baseUrl + path
206
- */
207
- return `${baseUrl}${path}`;
208
- }
209
- /**
210
- * Interactively prompt the user to login
211
- * @param url Path of the requested page
212
- */
213
- loginInteractively(state) {
214
- const authRequest = typeof this.msalGuardConfig.authRequest === "function"
215
- ? this.msalGuardConfig.authRequest(this.authService, state)
216
- : { ...this.msalGuardConfig.authRequest };
217
- if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
218
- this.authService.getLogger().verbose("Guard - logging in by popup");
219
- return this.authService.loginPopup(authRequest).pipe(map((response) => {
220
- this.authService
221
- .getLogger()
222
- .verbose("Guard - login by popup successful, can activate, setting active account");
223
- this.authService.instance.setActiveAccount(response.account);
224
- return true;
225
- }));
226
- }
227
- this.authService.getLogger().verbose("Guard - logging in by redirect");
228
- const redirectStartPage = this.getDestinationUrl(state.url);
229
- return this.authService
230
- .loginRedirect({
231
- redirectStartPage,
232
- ...authRequest,
233
- })
234
- .pipe(map(() => false));
235
- }
236
- /**
237
- * Helper which checks for the correct interaction type, prevents page with Guard to be set as redirect, and calls handleRedirectObservable
238
- * @param state
239
- */
240
- activateHelper(state) {
241
- if (this.msalGuardConfig.interactionType !== InteractionType.Popup &&
242
- this.msalGuardConfig.interactionType !== InteractionType.Redirect) {
243
- throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Guard. InteractionType.Popup or InteractionType.Redirect must be provided in the MsalGuardConfiguration");
244
- }
245
- this.authService.getLogger().verbose("MSAL Guard activated");
246
- /*
247
- * If a page with MSAL Guard is set as the redirect for acquireTokenSilent,
248
- * short-circuit to prevent redirecting or popups.
249
- */
250
- if (typeof window !== "undefined") {
251
- if (UrlString.hashContainsKnownProperties(window.location.hash) &&
252
- BrowserUtils.isInIframe() &&
253
- !this.authService.instance.getConfiguration().system
254
- .allowRedirectInIframe) {
255
- this.authService
256
- .getLogger()
257
- .warning("Guard - redirectUri set to page with MSAL Guard. It is recommended to not set redirectUri to a page that requires authentication.");
258
- return of(false);
259
- }
260
- }
261
- else {
262
- this.authService
263
- .getLogger()
264
- .info("Guard - window is undefined, MSAL does not support server-side token acquisition");
265
- return of(true);
266
- }
267
- /**
268
- * If a loginFailedRoute is set in the config, set this as the loginFailedRoute
269
- */
270
- if (this.msalGuardConfig.loginFailedRoute) {
271
- this.loginFailedRoute = this.parseUrl(this.msalGuardConfig.loginFailedRoute);
272
- }
273
- // Capture current path before it gets changed by handleRedirectObservable
274
- const currentPath = this.location.path(true);
275
- return this.authService.initialize().pipe(concatMap(() => {
276
- return this.authService.handleRedirectObservable();
277
- }), concatMap(() => {
278
- if (!this.authService.instance.getAllAccounts().length) {
279
- if (state) {
280
- this.authService
281
- .getLogger()
282
- .verbose("Guard - no accounts retrieved, log in required to activate");
283
- return this.loginInteractively(state);
284
- }
285
- this.authService
286
- .getLogger()
287
- .verbose("Guard - no accounts retrieved, no state, cannot load");
288
- return of(false);
289
- }
290
- this.authService
291
- .getLogger()
292
- .verbose("Guard - at least 1 account exists, can activate or load");
293
- // Prevent navigating the app to /#code= or /code=
294
- if (state) {
295
- /*
296
- * Path routing:
297
- * state.url: /#code=...
298
- * state.root.fragment: code=...
299
- */
300
- /*
301
- * Hash routing:
302
- * state.url: /code
303
- * state.root.fragment: null
304
- */
305
- const urlContainsCode = this.includesCode(state.url);
306
- const fragmentContainsCode = !!state.root &&
307
- !!state.root.fragment &&
308
- this.includesCode(`#${state.root.fragment}`);
309
- const hashRouting = this.location.prepareExternalUrl(state.url).indexOf("#") === 0;
310
- // Ensure code parameter is in fragment (and not in query parameter), or that hash hash routing is used
311
- if (urlContainsCode && (fragmentContainsCode || hashRouting)) {
312
- this.authService
313
- .getLogger()
314
- .info("Guard - Hash contains known code response, stopping navigation.");
315
- // Path routing (navigate to current path without hash)
316
- if (currentPath.indexOf("#") > -1) {
317
- return of(this.parseUrl(this.location.path()));
318
- }
319
- // Hash routing (navigate to root path)
320
- return of(this.parseUrl(""));
321
- }
322
- }
323
- return of(true);
324
- }), catchError((error) => {
325
- this.authService
326
- .getLogger()
327
- .error("Guard - error while logging in, unable to activate");
328
- this.authService
329
- .getLogger()
330
- .errorPii(`Guard - error: ${error.message}`);
331
- /**
332
- * If a loginFailedRoute is set, checks to see if state is passed before returning route
333
- */
334
- if (this.loginFailedRoute && state) {
335
- this.authService
336
- .getLogger()
337
- .verbose("Guard - loginFailedRoute set, redirecting");
338
- return of(this.loginFailedRoute);
339
- }
340
- return of(false);
341
- }));
342
- }
343
- includesCode(path) {
344
- return ((path.lastIndexOf("/code") > -1 &&
345
- path.lastIndexOf("/code") === path.length - "/code".length) || // path.endsWith("/code")
346
- path.indexOf("#code=") > -1 ||
347
- path.indexOf("&code=") > -1);
348
- }
349
- canActivate(route, state) {
350
- this.authService.getLogger().verbose("Guard - canActivate");
351
- return this.activateHelper(state);
352
- }
353
- canActivateChild(route, state) {
354
- this.authService.getLogger().verbose("Guard - canActivateChild");
355
- return this.activateHelper(state);
356
- }
357
- canMatch() {
358
- this.authService.getLogger().verbose("Guard - canLoad");
359
- return this.activateHelper();
360
- }
361
- }
362
- MsalGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard, deps: [{ token: MSAL_GUARD_CONFIG }, { token: MsalBroadcastService }, { token: MsalService }, { token: i3.Location }, { token: i4.Router }], target: i0.ɵɵFactoryTarget.Injectable });
363
- MsalGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard });
364
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalGuard, decorators: [{
365
- type: Injectable
366
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
367
- type: Inject,
368
- args: [MSAL_GUARD_CONFIG]
369
- }] }, { type: MsalBroadcastService }, { type: MsalService }, { type: i3.Location }, { type: i4.Router }]; } });
161
+ /*
162
+ * Copyright (c) Microsoft Corporation. All rights reserved.
163
+ * Licensed under the MIT License.
164
+ */
165
+ class MsalGuard {
166
+ constructor(msalGuardConfig, msalBroadcastService, authService, location, router) {
167
+ this.msalGuardConfig = msalGuardConfig;
168
+ this.msalBroadcastService = msalBroadcastService;
169
+ this.authService = authService;
170
+ this.location = location;
171
+ this.router = router;
172
+ // Subscribing so events in MsalGuard will set inProgress$ observable
173
+ this.msalBroadcastService.inProgress$.subscribe();
174
+ }
175
+ /**
176
+ * Parses url string to UrlTree
177
+ * @param url
178
+ */
179
+ parseUrl(url) {
180
+ return this.router.parseUrl(url);
181
+ }
182
+ /**
183
+ * Builds the absolute url for the destination page
184
+ * @param path Relative path of requested page
185
+ * @returns Full destination url
186
+ */
187
+ getDestinationUrl(path) {
188
+ this.authService.getLogger().verbose("Guard - getting destination url", "");
189
+ // Absolute base url for the application (default to origin if base element not present)
190
+ const baseElements = document.getElementsByTagName("base");
191
+ const baseUrl = this.location.normalize(baseElements.length ? baseElements[0].href : window.location.origin);
192
+ // Path of page (including hash, if using hash routing)
193
+ const pathUrl = this.location.prepareExternalUrl(path);
194
+ // Hash location strategy
195
+ if (pathUrl.startsWith("#")) {
196
+ this.authService
197
+ .getLogger()
198
+ .verbose("Guard - destination by hash routing", "");
199
+ return `${baseUrl}/${pathUrl}`;
200
+ }
201
+ /*
202
+ * If using path location strategy, pathUrl will include the relative portion of the base path (e.g. /base/page).
203
+ * Since baseUrl also includes /base, can just concatentate baseUrl + path
204
+ */
205
+ return `${baseUrl}${path}`;
206
+ }
207
+ /**
208
+ * Interactively prompt the user to login
209
+ * @param url Path of the requested page
210
+ */
211
+ loginInteractively(state) {
212
+ const authRequest = typeof this.msalGuardConfig.authRequest === "function"
213
+ ? this.msalGuardConfig.authRequest(this.authService, state)
214
+ : { ...this.msalGuardConfig.authRequest };
215
+ if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
216
+ this.authService
217
+ .getLogger()
218
+ .verbose("Guard - logging in by popup", authRequest.correlationId);
219
+ return this.authService.loginPopup(authRequest).pipe(map((response) => {
220
+ this.authService
221
+ .getLogger()
222
+ .verbose("Guard - login by popup successful, can activate, setting active account", authRequest.correlationId);
223
+ this.authService.instance.setActiveAccount(response.account);
224
+ return true;
225
+ }));
226
+ }
227
+ this.authService
228
+ .getLogger()
229
+ .verbose("Guard - logging in by redirect", authRequest.correlationId);
230
+ const redirectStartPage = this.getDestinationUrl(state.url);
231
+ return this.authService
232
+ .loginRedirect({
233
+ redirectStartPage,
234
+ ...authRequest,
235
+ })
236
+ .pipe(map(() => false));
237
+ }
238
+ /**
239
+ * Helper which checks for the correct interaction type, prevents page with Guard to be set as redirect, and calls handleRedirectObservable
240
+ * @param state
241
+ */
242
+ activateHelper(state) {
243
+ if (this.msalGuardConfig.interactionType !== InteractionType.Popup &&
244
+ this.msalGuardConfig.interactionType !== InteractionType.Redirect) {
245
+ throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Guard. InteractionType.Popup or InteractionType.Redirect must be provided in the MsalGuardConfiguration");
246
+ }
247
+ this.authService.getLogger().verbose("MSAL Guard activated", "");
248
+ /*
249
+ * If a page with MSAL Guard is set as the redirect for acquireTokenSilent,
250
+ * short-circuit to prevent redirecting or popups.
251
+ */
252
+ if (typeof window === "undefined") {
253
+ this.authService
254
+ .getLogger()
255
+ .info("Guard - window is undefined, MSAL does not support server-side token acquisition", "");
256
+ return of(true);
257
+ }
258
+ else {
259
+ try {
260
+ BrowserUtils.blockReloadInHiddenIframes();
261
+ }
262
+ catch (error) {
263
+ if (!this.authService.instance.getConfiguration().system
264
+ .allowRedirectInIframe) {
265
+ this.authService
266
+ .getLogger()
267
+ .warning("Guard - redirectUri set to page with MSAL Guard. It is recommended to not set redirectUri to a page that requires authentication.", "");
268
+ return of(false);
269
+ }
270
+ }
271
+ }
272
+ /**
273
+ * If a loginFailedRoute is set in the config, set this as the loginFailedRoute
274
+ */
275
+ if (this.msalGuardConfig.loginFailedRoute) {
276
+ this.loginFailedRoute = this.parseUrl(this.msalGuardConfig.loginFailedRoute);
277
+ }
278
+ // Capture current path before it gets changed by handleRedirectObservable
279
+ const currentPath = this.location.path(true);
280
+ return this.authService.initialize().pipe(concatMap(() => {
281
+ return this.authService.handleRedirectObservable();
282
+ }), concatMap(() => {
283
+ if (!this.authService.instance.getAllAccounts().length) {
284
+ if (state) {
285
+ this.authService
286
+ .getLogger()
287
+ .verbose("Guard - no accounts retrieved, log in required to activate", "");
288
+ return this.loginInteractively(state);
289
+ }
290
+ this.authService
291
+ .getLogger()
292
+ .verbose("Guard - no accounts retrieved, no state, cannot load", "");
293
+ return of(false);
294
+ }
295
+ this.authService
296
+ .getLogger()
297
+ .verbose("Guard - at least 1 account exists, can activate or load", "");
298
+ // Prevent navigating the app to /#code= or /code=
299
+ if (state) {
300
+ /*
301
+ * Path routing:
302
+ * state.url: /#code=...
303
+ * state.root.fragment: code=...
304
+ */
305
+ /*
306
+ * Hash routing:
307
+ * state.url: /code
308
+ * state.root.fragment: null
309
+ */
310
+ const urlContainsCode = this.includesCode(state.url);
311
+ const fragmentContainsCode = !!state.root &&
312
+ !!state.root.fragment &&
313
+ this.includesCode(`#${state.root.fragment}`);
314
+ const hashRouting = this.location.prepareExternalUrl(state.url).indexOf("#") === 0;
315
+ // Ensure code parameter is in fragment (and not in query parameter), or that hash hash routing is used
316
+ if (urlContainsCode && (fragmentContainsCode || hashRouting)) {
317
+ this.authService
318
+ .getLogger()
319
+ .info("Guard - Hash contains known code response, stopping navigation.", "");
320
+ // Path routing (navigate to current path without hash)
321
+ if (currentPath.indexOf("#") > -1) {
322
+ return of(this.parseUrl(this.location.path()));
323
+ }
324
+ // Hash routing (navigate to root path)
325
+ return of(this.parseUrl(""));
326
+ }
327
+ }
328
+ return of(true);
329
+ }), catchError((error) => {
330
+ this.authService
331
+ .getLogger()
332
+ .error("Guard - error while logging in, unable to activate", "");
333
+ this.authService
334
+ .getLogger()
335
+ .errorPii(`Guard - error: ${error.message}`, "");
336
+ /**
337
+ * If a loginFailedRoute is set, checks to see if state is passed before returning route
338
+ */
339
+ if (this.loginFailedRoute && state) {
340
+ this.authService
341
+ .getLogger()
342
+ .verbose("Guard - loginFailedRoute set, redirecting", "");
343
+ return of(this.loginFailedRoute);
344
+ }
345
+ return of(false);
346
+ }));
347
+ }
348
+ includesCode(path) {
349
+ return ((path.lastIndexOf("/code") > -1 &&
350
+ path.lastIndexOf("/code") === path.length - "/code".length) || // path.endsWith("/code")
351
+ path.indexOf("#code=") > -1 ||
352
+ path.indexOf("&code=") > -1);
353
+ }
354
+ canActivate(route, state) {
355
+ this.authService.getLogger().verbose("Guard - canActivate", "");
356
+ return this.activateHelper(state);
357
+ }
358
+ canActivateChild(route, state) {
359
+ this.authService.getLogger().verbose("Guard - canActivateChild", "");
360
+ return this.activateHelper(state);
361
+ }
362
+ canMatch() {
363
+ this.authService.getLogger().verbose("Guard - canLoad", "");
364
+ return this.activateHelper();
365
+ }
366
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalGuard, deps: [{ token: MSAL_GUARD_CONFIG }, { token: MsalBroadcastService }, { token: MsalService }, { token: i3.Location }, { token: i4.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
367
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalGuard }); }
368
+ }
369
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalGuard, decorators: [{
370
+ type: Injectable
371
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
372
+ type: Inject,
373
+ args: [MSAL_GUARD_CONFIG]
374
+ }] }, { type: MsalBroadcastService }, { type: MsalService }, { type: i3.Location }, { type: i4.Router }] });
370
375
 
371
- /*
372
- * Copyright (c) Microsoft Corporation. All rights reserved.
373
- * Licensed under the MIT License.
374
- */
375
- class MsalInterceptor {
376
- constructor(msalInterceptorConfig, authService, location, msalBroadcastService,
377
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
378
- document) {
379
- this.msalInterceptorConfig = msalInterceptorConfig;
380
- this.authService = authService;
381
- this.location = location;
382
- this.msalBroadcastService = msalBroadcastService;
383
- this._document = document;
384
- }
385
- intercept(req, // eslint-disable-line @typescript-eslint/no-explicit-any
386
- next
387
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
388
- ) {
389
- if (this.msalInterceptorConfig.interactionType !== InteractionType.Popup &&
390
- this.msalInterceptorConfig.interactionType !== InteractionType.Redirect) {
391
- throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Interceptor. InteractionType.Popup, InteractionType.Redirect must be provided in the msalInterceptorConfiguration");
392
- }
393
- this.authService.getLogger().verbose("MSAL Interceptor activated");
394
- const scopes = this.getScopesForEndpoint(req.url, req.method);
395
- // If no scopes for endpoint, does not acquire token
396
- if (!scopes || scopes.length === 0) {
397
- this.authService
398
- .getLogger()
399
- .verbose("Interceptor - no scopes for endpoint");
400
- return next.handle(req);
401
- }
402
- // Sets account as active account or first account
403
- let account;
404
- if (!!this.authService.instance.getActiveAccount()) {
405
- this.authService
406
- .getLogger()
407
- .verbose("Interceptor - active account selected");
408
- account = this.authService.instance.getActiveAccount();
409
- }
410
- else {
411
- this.authService
412
- .getLogger()
413
- .verbose("Interceptor - no active account, fallback to first account");
414
- account = this.authService.instance.getAllAccounts()[0];
415
- }
416
- const authRequest = typeof this.msalInterceptorConfig.authRequest === "function"
417
- ? this.msalInterceptorConfig.authRequest(this.authService, req, {
418
- account: account,
419
- })
420
- : { ...this.msalInterceptorConfig.authRequest, account };
421
- this.authService
422
- .getLogger()
423
- .info(`Interceptor - ${scopes.length} scopes found for endpoint`);
424
- this.authService
425
- .getLogger()
426
- .infoPii(`Interceptor - [${scopes}] scopes found for ${req.url}`);
427
- return this.acquireToken(authRequest, scopes, account).pipe(switchMap((result) => {
428
- this.authService
429
- .getLogger()
430
- .verbose("Interceptor - setting authorization headers");
431
- const headers = req.headers.set("Authorization", `Bearer ${result.accessToken}`);
432
- const requestClone = req.clone({ headers });
433
- return next.handle(requestClone);
434
- }));
435
- }
436
- /**
437
- * Try to acquire token silently. Invoke interaction if acquireTokenSilent rejected with error or resolved with null access token
438
- * @param authRequest Request
439
- * @param scopes Array of scopes for the request
440
- * @param account Account
441
- * @returns Authentication result
442
- */
443
- acquireToken(authRequest, scopes, account) {
444
- // Note: For MSA accounts, include openid scope when calling acquireTokenSilent to return idToken
445
- return this.authService
446
- .acquireTokenSilent({ ...authRequest, scopes, account })
447
- .pipe(catchError(() => {
448
- this.authService
449
- .getLogger()
450
- .error("Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.");
451
- return this.msalBroadcastService.inProgress$.pipe(take(1), switchMap((status) => {
452
- if (status === InteractionStatus.None) {
453
- return this.acquireTokenInteractively(authRequest, scopes);
454
- }
455
- return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireToken(authRequest, scopes, account)));
456
- }));
457
- }), switchMap((result) => {
458
- if (!result.accessToken) {
459
- this.authService
460
- .getLogger()
461
- .error("Interceptor - acquireTokenSilent resolved with null access token. Known issue with B2C tenants, invoking interaction to resolve.");
462
- return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireTokenInteractively(authRequest, scopes)));
463
- }
464
- return of(result);
465
- }));
466
- }
467
- /**
468
- * Invoke interaction for the given set of scopes
469
- * @param authRequest Request
470
- * @param scopes Array of scopes for the request
471
- * @returns Result from the interactive request
472
- */
473
- acquireTokenInteractively(authRequest, scopes) {
474
- if (this.msalInterceptorConfig.interactionType === InteractionType.Popup) {
475
- this.authService
476
- .getLogger()
477
- .verbose("Interceptor - error acquiring token silently, acquiring by popup");
478
- return this.authService.acquireTokenPopup({ ...authRequest, scopes });
479
- }
480
- this.authService
481
- .getLogger()
482
- .verbose("Interceptor - error acquiring token silently, acquiring by redirect");
483
- const redirectStartPage = window.location.href;
484
- this.authService.acquireTokenRedirect({
485
- ...authRequest,
486
- scopes,
487
- redirectStartPage,
488
- });
489
- return EMPTY;
490
- }
491
- /**
492
- * Looks up the scopes for the given endpoint from the protectedResourceMap
493
- * @param endpoint Url of the request
494
- * @param httpMethod Http method of the request
495
- * @returns Array of scopes, or null if not found
496
- *
497
- */
498
- getScopesForEndpoint(endpoint, httpMethod) {
499
- this.authService
500
- .getLogger()
501
- .verbose("Interceptor - getting scopes for endpoint");
502
- // Ensures endpoints and protected resources compared are normalized
503
- const normalizedEndpoint = this.location.normalize(endpoint);
504
- const protectedResourcesArray = Array.from(this.msalInterceptorConfig.protectedResourceMap.keys());
505
- const matchingProtectedResources = this.matchResourcesToEndpoint(protectedResourcesArray, normalizedEndpoint);
506
- if (matchingProtectedResources.length > 0) {
507
- return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources, httpMethod);
508
- }
509
- return null;
510
- }
511
- /**
512
- * Finds resource endpoints that match request endpoint
513
- * @param protectedResourcesEndpoints
514
- * @param endpoint
515
- * @returns
516
- */
517
- matchResourcesToEndpoint(protectedResourcesEndpoints, endpoint) {
518
- const matchingResources = [];
519
- protectedResourcesEndpoints.forEach((key) => {
520
- const normalizedKey = this.location.normalize(key);
521
- // Get url components
522
- const absoluteKey = this.getAbsoluteUrl(normalizedKey);
523
- const keyComponents = new URL(absoluteKey);
524
- const absoluteEndpoint = this.getAbsoluteUrl(endpoint);
525
- const endpointComponents = new URL(absoluteEndpoint);
526
- if (this.checkUrlComponents(keyComponents, endpointComponents)) {
527
- matchingResources.push(key);
528
- }
529
- });
530
- return matchingResources;
531
- }
532
- /**
533
- * Compares URL segments between key and endpoint
534
- * @param key
535
- * @param endpoint
536
- * @returns
537
- */
538
- checkUrlComponents(keyComponents, endpointComponents) {
539
- // URL properties from https://developer.mozilla.org/en-US/docs/Web/API/URL
540
- const urlProperties = ["protocol", "host", "pathname", "search", "hash"];
541
- for (const property of urlProperties) {
542
- if (keyComponents[property]) {
543
- const decodedInput = decodeURIComponent(keyComponents[property]);
544
- if (!StringUtils.matchPattern(decodedInput, endpointComponents[property])) {
545
- return false;
546
- }
547
- }
548
- }
549
- return true;
550
- }
551
- /**
552
- * Transforms relative urls to absolute urls
553
- * @param url
554
- * @returns
555
- */
556
- getAbsoluteUrl(url) {
557
- const link = this._document.createElement("a");
558
- link.href = url;
559
- return link.href;
560
- }
561
- /**
562
- * Finds scopes from first matching endpoint with HTTP method that matches request
563
- * @param protectedResourceMap Protected resource map
564
- * @param endpointArray Array of resources that match request endpoint
565
- * @param httpMethod Http method of the request
566
- * @returns
567
- */
568
- matchScopesToEndpoint(protectedResourceMap, endpointArray, httpMethod) {
569
- const allMatchedScopes = [];
570
- // Check each matched endpoint for matching HttpMethod and scopes
571
- endpointArray.forEach((matchedEndpoint) => {
572
- const scopesForEndpoint = [];
573
- const methodAndScopesArray = protectedResourceMap.get(matchedEndpoint);
574
- // Return if resource is unprotected
575
- if (methodAndScopesArray === null) {
576
- allMatchedScopes.push(null);
577
- return;
578
- }
579
- methodAndScopesArray.forEach((entry) => {
580
- // Entry is either array of scopes or ProtectedResourceScopes object
581
- if (typeof entry === "string") {
582
- scopesForEndpoint.push(entry);
583
- }
584
- else {
585
- // Ensure methods being compared are normalized
586
- const normalizedRequestMethod = httpMethod.toLowerCase();
587
- const normalizedResourceMethod = entry.httpMethod.toLowerCase();
588
- // Method in protectedResourceMap matches request http method
589
- if (normalizedResourceMethod === normalizedRequestMethod) {
590
- // Validate if scopes comes null to unprotect the resource in a certain http method
591
- if (entry.scopes === null) {
592
- allMatchedScopes.push(null);
593
- }
594
- else {
595
- entry.scopes.forEach((scope) => {
596
- scopesForEndpoint.push(scope);
597
- });
598
- }
599
- }
600
- }
601
- });
602
- // Only add to all scopes if scopes for endpoint and method is found
603
- if (scopesForEndpoint.length > 0) {
604
- allMatchedScopes.push(scopesForEndpoint);
605
- }
606
- });
607
- if (allMatchedScopes.length > 0) {
608
- if (allMatchedScopes.length > 1) {
609
- this.authService
610
- .getLogger()
611
- .warning("Interceptor - More than 1 matching scopes for endpoint found.");
612
- }
613
- // Returns scopes for first matching endpoint
614
- return allMatchedScopes[0];
615
- }
616
- return null;
617
- }
618
- }
619
- MsalInterceptorfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor, deps: [{ token: MSAL_INTERCEPTOR_CONFIG }, { token: MsalService }, { token: i3.Location }, { token: MsalBroadcastService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
620
- MsalInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor });
621
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalInterceptor, decorators: [{
622
- type: Injectable
623
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
624
- type: Inject,
625
- args: [MSAL_INTERCEPTOR_CONFIG]
626
- }] }, { type: MsalService }, { type: i3.Location }, { type: MsalBroadcastService }, { type: undefined, decorators: [{
627
- type: Inject,
628
- args: [DOCUMENT]
629
- }] }]; } });
376
+ /*
377
+ * Copyright (c) Microsoft Corporation. All rights reserved.
378
+ * Licensed under the MIT License.
379
+ */
380
+ class MsalInterceptor {
381
+ constructor(msalInterceptorConfig, authService, location, msalBroadcastService,
382
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
383
+ document) {
384
+ this.msalInterceptorConfig = msalInterceptorConfig;
385
+ this.authService = authService;
386
+ this.location = location;
387
+ this.msalBroadcastService = msalBroadcastService;
388
+ this._document = document;
389
+ }
390
+ intercept(req, // eslint-disable-line @typescript-eslint/no-explicit-any
391
+ next
392
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
393
+ ) {
394
+ if (this.msalInterceptorConfig.interactionType !== InteractionType.Popup &&
395
+ this.msalInterceptorConfig.interactionType !== InteractionType.Redirect) {
396
+ throw new BrowserConfigurationAuthError("invalid_interaction_type", "Invalid interaction type provided to MSAL Interceptor. InteractionType.Popup, InteractionType.Redirect must be provided in the msalInterceptorConfiguration");
397
+ }
398
+ this.authService.getLogger().verbose("MSAL Interceptor activated", "");
399
+ const scopes = this.getScopesForEndpoint(req.url, req.method);
400
+ // If no scopes for endpoint, does not acquire token
401
+ if (!scopes || scopes.length === 0) {
402
+ this.authService
403
+ .getLogger()
404
+ .verbose("Interceptor - no scopes for endpoint", "");
405
+ return next.handle(req);
406
+ }
407
+ // Sets account as active account or first account
408
+ let account;
409
+ if (!!this.authService.instance.getActiveAccount()) {
410
+ this.authService
411
+ .getLogger()
412
+ .verbose("Interceptor - active account selected", "");
413
+ account = this.authService.instance.getActiveAccount();
414
+ }
415
+ else {
416
+ this.authService
417
+ .getLogger()
418
+ .verbose("Interceptor - no active account, fallback to first account", "");
419
+ account = this.authService.instance.getAllAccounts()[0];
420
+ }
421
+ const authRequest = typeof this.msalInterceptorConfig.authRequest === "function"
422
+ ? this.msalInterceptorConfig.authRequest(this.authService, req, {
423
+ account: account,
424
+ })
425
+ : { ...this.msalInterceptorConfig.authRequest, account };
426
+ this.authService
427
+ .getLogger()
428
+ .info(`Interceptor - ${scopes.length} scopes found for endpoint`, "");
429
+ this.authService
430
+ .getLogger()
431
+ .infoPii(`Interceptor - [${scopes}] scopes found for ${req.url}`, "");
432
+ return this.acquireToken(authRequest, scopes, account).pipe(switchMap((result) => {
433
+ this.authService
434
+ .getLogger()
435
+ .verbose("Interceptor - setting authorization headers", "");
436
+ const headers = req.headers.set("Authorization", `Bearer ${result.accessToken}`);
437
+ const requestClone = req.clone({ headers });
438
+ return next.handle(requestClone);
439
+ }));
440
+ }
441
+ /**
442
+ * Try to acquire token silently. Invoke interaction if acquireTokenSilent rejected with error or resolved with null access token
443
+ * @param authRequest Request
444
+ * @param scopes Array of scopes for the request
445
+ * @param account Account
446
+ * @returns Authentication result
447
+ */
448
+ acquireToken(authRequest, scopes, account) {
449
+ // Note: For MSA accounts, include openid scope when calling acquireTokenSilent to return idToken
450
+ return this.authService
451
+ .acquireTokenSilent({ ...authRequest, scopes, account })
452
+ .pipe(catchError(() => {
453
+ this.authService
454
+ .getLogger()
455
+ .error("Interceptor - acquireTokenSilent rejected with error. Invoking interaction to resolve.", authRequest.correlationId);
456
+ return this.msalBroadcastService.inProgress$.pipe(take(1), switchMap((status) => {
457
+ if (status === InteractionStatus.None) {
458
+ return this.acquireTokenInteractively(authRequest, scopes);
459
+ }
460
+ return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireToken(authRequest, scopes, account)));
461
+ }));
462
+ }), switchMap((result) => {
463
+ if (!result.accessToken) {
464
+ this.authService
465
+ .getLogger()
466
+ .error("Interceptor - acquireTokenSilent resolved with null access token. Known issue with B2C tenants, invoking interaction to resolve.", authRequest.correlationId);
467
+ return this.msalBroadcastService.inProgress$.pipe(filter((status) => status === InteractionStatus.None), take(1), switchMap(() => this.acquireTokenInteractively(authRequest, scopes)));
468
+ }
469
+ return of(result);
470
+ }));
471
+ }
472
+ /**
473
+ * Invoke interaction for the given set of scopes
474
+ * @param authRequest Request
475
+ * @param scopes Array of scopes for the request
476
+ * @returns Result from the interactive request
477
+ */
478
+ acquireTokenInteractively(authRequest, scopes) {
479
+ if (this.msalInterceptorConfig.interactionType === InteractionType.Popup) {
480
+ this.authService
481
+ .getLogger()
482
+ .verbose("Interceptor - error acquiring token silently, acquiring by popup", authRequest.correlationId);
483
+ return this.authService.acquireTokenPopup({ ...authRequest, scopes });
484
+ }
485
+ this.authService
486
+ .getLogger()
487
+ .verbose("Interceptor - error acquiring token silently, acquiring by redirect", authRequest.correlationId);
488
+ const redirectStartPage = window.location.href;
489
+ this.authService.acquireTokenRedirect({
490
+ ...authRequest,
491
+ scopes,
492
+ redirectStartPage,
493
+ });
494
+ return EMPTY;
495
+ }
496
+ /**
497
+ * Looks up the scopes for the given endpoint from the protectedResourceMap
498
+ * @param endpoint Url of the request
499
+ * @param httpMethod Http method of the request
500
+ * @returns Array of scopes, or null if not found
501
+ *
502
+ */
503
+ getScopesForEndpoint(endpoint, httpMethod) {
504
+ this.authService
505
+ .getLogger()
506
+ .verbose("Interceptor - getting scopes for endpoint", "");
507
+ // Ensures endpoints and protected resources compared are normalized
508
+ const normalizedEndpoint = this.location.normalize(endpoint);
509
+ const protectedResourcesArray = Array.from(this.msalInterceptorConfig.protectedResourceMap.keys());
510
+ const matchingProtectedResources = this.matchResourcesToEndpoint(protectedResourcesArray, normalizedEndpoint);
511
+ if (matchingProtectedResources.length > 0) {
512
+ return this.matchScopesToEndpoint(this.msalInterceptorConfig.protectedResourceMap, matchingProtectedResources, httpMethod);
513
+ }
514
+ return null;
515
+ }
516
+ /**
517
+ * Finds resource endpoints that match request endpoint
518
+ * @param protectedResourcesEndpoints
519
+ * @param endpoint
520
+ * @returns
521
+ */
522
+ matchResourcesToEndpoint(protectedResourcesEndpoints, endpoint) {
523
+ const matchingResources = [];
524
+ protectedResourcesEndpoints.forEach((key) => {
525
+ const normalizedKey = this.location.normalize(key);
526
+ // Get url components
527
+ const absoluteKey = this.getAbsoluteUrl(normalizedKey);
528
+ const keyComponents = new URL(absoluteKey);
529
+ const absoluteEndpoint = this.getAbsoluteUrl(endpoint);
530
+ const endpointComponents = new URL(absoluteEndpoint);
531
+ if (this.checkUrlComponents(keyComponents, endpointComponents)) {
532
+ matchingResources.push(key);
533
+ }
534
+ });
535
+ return matchingResources;
536
+ }
537
+ /**
538
+ * Compares URL segments between key and endpoint
539
+ * @param key
540
+ * @param endpoint
541
+ * @returns
542
+ */
543
+ checkUrlComponents(keyComponents, endpointComponents) {
544
+ // URL properties from https://developer.mozilla.org/en-US/docs/Web/API/URL
545
+ const urlProperties = ["protocol", "host", "pathname", "search", "hash"];
546
+ for (const property of urlProperties) {
547
+ if (keyComponents[property]) {
548
+ const decodedInput = decodeURIComponent(keyComponents[property]);
549
+ if (!StringUtils.matchPattern(decodedInput, endpointComponents[property])) {
550
+ return false;
551
+ }
552
+ }
553
+ }
554
+ return true;
555
+ }
556
+ /**
557
+ * Transforms relative urls to absolute urls
558
+ * @param url
559
+ * @returns
560
+ */
561
+ getAbsoluteUrl(url) {
562
+ const link = this._document.createElement("a");
563
+ link.href = url;
564
+ return link.href;
565
+ }
566
+ /**
567
+ * Finds scopes from first matching endpoint with HTTP method that matches request
568
+ * @param protectedResourceMap Protected resource map
569
+ * @param endpointArray Array of resources that match request endpoint
570
+ * @param httpMethod Http method of the request
571
+ * @returns
572
+ */
573
+ matchScopesToEndpoint(protectedResourceMap, endpointArray, httpMethod) {
574
+ const allMatchedScopes = [];
575
+ // Check each matched endpoint for matching HttpMethod and scopes
576
+ endpointArray.forEach((matchedEndpoint) => {
577
+ const scopesForEndpoint = [];
578
+ const methodAndScopesArray = protectedResourceMap.get(matchedEndpoint);
579
+ // Return if resource is unprotected
580
+ if (methodAndScopesArray === null) {
581
+ allMatchedScopes.push(null);
582
+ return;
583
+ }
584
+ methodAndScopesArray.forEach((entry) => {
585
+ // Entry is either array of scopes or ProtectedResourceScopes object
586
+ if (typeof entry === "string") {
587
+ scopesForEndpoint.push(entry);
588
+ }
589
+ else {
590
+ // Ensure methods being compared are normalized
591
+ const normalizedRequestMethod = httpMethod.toLowerCase();
592
+ const normalizedResourceMethod = entry.httpMethod.toLowerCase();
593
+ // Method in protectedResourceMap matches request http method
594
+ if (normalizedResourceMethod === normalizedRequestMethod) {
595
+ // Validate if scopes comes null to unprotect the resource in a certain http method
596
+ if (entry.scopes === null) {
597
+ allMatchedScopes.push(null);
598
+ }
599
+ else {
600
+ entry.scopes.forEach((scope) => {
601
+ scopesForEndpoint.push(scope);
602
+ });
603
+ }
604
+ }
605
+ }
606
+ });
607
+ // Only add to all scopes if scopes for endpoint and method is found
608
+ if (scopesForEndpoint.length > 0) {
609
+ allMatchedScopes.push(scopesForEndpoint);
610
+ }
611
+ });
612
+ if (allMatchedScopes.length > 0) {
613
+ if (allMatchedScopes.length > 1) {
614
+ this.authService
615
+ .getLogger()
616
+ .warning("Interceptor - More than 1 matching scopes for endpoint found.", "");
617
+ }
618
+ // Returns scopes for first matching endpoint
619
+ return allMatchedScopes[0];
620
+ }
621
+ return null;
622
+ }
623
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalInterceptor, deps: [{ token: MSAL_INTERCEPTOR_CONFIG }, { token: MsalService }, { token: i3.Location }, { token: MsalBroadcastService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
624
+ static { thisprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalInterceptor }); }
625
+ }
626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalInterceptor, decorators: [{
627
+ type: Injectable
628
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
629
+ type: Inject,
630
+ args: [MSAL_INTERCEPTOR_CONFIG]
631
+ }] }, { type: MsalService }, { type: i3.Location }, { type: MsalBroadcastService }, { type: undefined, decorators: [{
632
+ type: Inject,
633
+ args: [DOCUMENT]
634
+ }] }] });
630
635
 
631
- /*
632
- * Copyright (c) Microsoft Corporation. All rights reserved.
633
- * Licensed under the MIT License.
634
- */
635
- /**
636
- * This is a dedicated redirect component to be added to Angular apps to
637
- * handle redirects when using @azure/msal-angular.
638
- * Import this component to use redirects in your app.
639
- */
640
- class MsalRedirectComponent {
641
- constructor(authService) {
642
- this.authService = authService;
643
- }
644
- ngOnInit() {
645
- this.authService.getLogger().verbose("MsalRedirectComponent activated");
646
- this.authService.handleRedirectObservable().subscribe();
647
- }
648
- }
649
- MsalRedirectComponentfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalRedirectComponent, deps: [{ token: MsalService }], target: i0.ɵɵFactoryTarget.Component });
650
- MsalRedirectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MsalRedirectComponent, selector: "app-redirect", ngImport: i0, template: "", isInline: true });
651
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalRedirectComponent, decorators: [{
652
- type: Component,
653
- args: [{
654
- selector: "app-redirect",
655
- template: "",
656
- }]
657
- }], ctorParameters: function () { return [{ type: MsalService }]; } });
636
+ /*
637
+ * Copyright (c) Microsoft Corporation. All rights reserved.
638
+ * Licensed under the MIT License.
639
+ */
640
+ /**
641
+ * This is a dedicated redirect component to be added to Angular apps to
642
+ * handle redirects when using @azure/msal-angular.
643
+ * Import this component to use redirects in your app.
644
+ */
645
+ class MsalRedirectComponent {
646
+ constructor(authService) {
647
+ this.authService = authService;
648
+ }
649
+ ngOnInit() {
650
+ this.authService.getLogger().verbose("MsalRedirectComponent activated", "");
651
+ this.authService.handleRedirectObservable().subscribe();
652
+ }
653
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalRedirectComponent, deps: [{ token: MsalService }], target: i0.ɵɵFactoryTarget.Component }); }
654
+ static { thiscmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: MsalRedirectComponent, isStandalone: false, selector: "app-redirect", ngImport: i0, template: "", isInline: true }); }
655
+ }
656
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalRedirectComponent, decorators: [{
657
+ type: Component,
658
+ args: [{
659
+ selector: "app-redirect",
660
+ template: "",
661
+ standalone: false,
662
+ }]
663
+ }], ctorParameters: () => [{ type: MsalService }] });
658
664
 
659
- /*
660
- * Copyright (c) Microsoft Corporation. All rights reserved.
661
- * Licensed under the MIT License.
662
- */
663
- class MsalModule {
664
- static forRoot(msalInstance, guardConfig, interceptorConfig) {
665
- return {
666
- ngModule: MsalModule,
667
- providers: [
668
- {
669
- provide: MSAL_INSTANCE,
670
- useValue: msalInstance,
671
- },
672
- {
673
- provide: MSAL_GUARD_CONFIG,
674
- useValue: guardConfig,
675
- },
676
- {
677
- provide: MSAL_INTERCEPTOR_CONFIG,
678
- useValue: interceptorConfig,
679
- },
680
- MsalService,
681
- ],
682
- };
683
- }
684
- }
685
- MsalModulefac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
686
- MsalModulemod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, declarations: [MsalRedirectComponent], imports: [CommonModule] });
687
- MsalModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, providers: [MsalGuard, MsalBroadcastService], imports: [CommonModule] });
688
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalModule, decorators: [{
689
- type: NgModule,
690
- args: [{
691
- declarations: [MsalRedirectComponent],
692
- imports: [CommonModule],
693
- providers: [MsalGuard, MsalBroadcastService],
694
- }]
665
+ /*
666
+ * Copyright (c) Microsoft Corporation. All rights reserved.
667
+ * Licensed under the MIT License.
668
+ */
669
+ class MsalModule {
670
+ static forRoot(msalInstance, guardConfig, interceptorConfig) {
671
+ return {
672
+ ngModule: MsalModule,
673
+ providers: [
674
+ {
675
+ provide: MSAL_INSTANCE,
676
+ useValue: msalInstance,
677
+ },
678
+ {
679
+ provide: MSAL_GUARD_CONFIG,
680
+ useValue: guardConfig,
681
+ },
682
+ {
683
+ provide: MSAL_INTERCEPTOR_CONFIG,
684
+ useValue: interceptorConfig,
685
+ },
686
+ MsalService,
687
+ ],
688
+ };
689
+ }
690
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
691
+ static { thismod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.15", ngImport: i0, type: MsalModule, declarations: [MsalRedirectComponent], imports: [CommonModule] }); }
692
+ static { thisinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalModule, providers: [MsalGuard, MsalBroadcastService], imports: [CommonModule] }); }
693
+ }
694
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalModule, decorators: [{
695
+ type: NgModule,
696
+ args: [{
697
+ declarations: [MsalRedirectComponent],
698
+ imports: [CommonModule],
699
+ providers: [MsalGuard, MsalBroadcastService],
700
+ }]
695
701
  }] });
696
702
 
697
- /*
698
- * Copyright (c) Microsoft Corporation. All rights reserved.
699
- * Licensed under the MIT License.
700
- */
701
- /**
702
- * Custom navigation used for Angular client-side navigation.
703
- * See performance doc for details:
704
- * https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular/docs/performance.md
705
- */
706
- class MsalCustomNavigationClient extends NavigationClient {
707
- constructor(authService, router, location) {
708
- super();
709
- this.authService = authService;
710
- this.router = router;
711
- this.location = location;
712
- }
713
- async navigateInternal(url, options) {
714
- this.authService.getLogger().trace("MsalCustomNavigationClient called");
715
- this.authService
716
- .getLogger()
717
- .verbose("MsalCustomNavigationClient - navigating");
718
- this.authService
719
- .getLogger()
720
- .verbosePii(`MsalCustomNavigationClient - navigating to url: ${url}`);
721
- // Prevent hash clearing from causing an issue with Client-side navigation after redirect is handled
722
- if (options.noHistory) {
723
- return super.navigateInternal(url, options);
724
- }
725
- else {
726
- // Normalizing newUrl if no query string
727
- const urlComponents = new UrlString(url).getUrlComponents();
728
- const newUrl = urlComponents.QueryString
729
- ? `${urlComponents.AbsolutePath}?${urlComponents.QueryString}`
730
- : this.location.normalize(urlComponents.AbsolutePath);
731
- await this.router.navigateByUrl(newUrl, {
732
- replaceUrl: options.noHistory,
733
- });
734
- }
735
- return Promise.resolve(options.noHistory);
736
- }
737
- }
738
- MsalCustomNavigationClientfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient, deps: [{ token: MsalService }, { token: i4.Router }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Injectable });
739
- MsalCustomNavigationClient.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient });
740
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsalCustomNavigationClient, decorators: [{
741
- type: Injectable
742
- }], ctorParameters: function () { return [{ type: MsalService }, { type: i4.Router }, { type: i3.Location }]; } });
703
+ /*
704
+ * Copyright (c) Microsoft Corporation. All rights reserved.
705
+ * Licensed under the MIT License.
706
+ */
707
+ /**
708
+ * Custom navigation used for Angular client-side navigation.
709
+ * See performance doc for details:
710
+ * https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular/docs/performance.md
711
+ */
712
+ class MsalCustomNavigationClient extends NavigationClient {
713
+ constructor(authService, router, location) {
714
+ super();
715
+ this.authService = authService;
716
+ this.router = router;
717
+ this.location = location;
718
+ }
719
+ async navigateInternal(url, options) {
720
+ this.authService.getLogger().trace("MsalCustomNavigationClient called", "");
721
+ this.authService
722
+ .getLogger()
723
+ .verbose("MsalCustomNavigationClient - navigating", "");
724
+ this.authService
725
+ .getLogger()
726
+ .verbosePii(`MsalCustomNavigationClient - navigating to url: ${url}`, "");
727
+ // Prevent hash clearing from causing an issue with Client-side navigation after redirect is handled
728
+ if (options.noHistory) {
729
+ return super.navigateInternal(url, options);
730
+ }
731
+ else {
732
+ // Normalizing newUrl if no query string
733
+ const urlComponents = new UrlString(url).getUrlComponents();
734
+ const newUrl = urlComponents.QueryString
735
+ ? `${urlComponents.AbsolutePath}?${urlComponents.QueryString}`
736
+ : this.location.normalize(urlComponents.AbsolutePath);
737
+ await this.router.navigateByUrl(newUrl, {
738
+ replaceUrl: options.noHistory,
739
+ });
740
+ }
741
+ return Promise.resolve(options.noHistory);
742
+ }
743
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalCustomNavigationClient, deps: [{ token: MsalService }, { token: i4.Router }, { token: i3.Location }], target: i0.ɵɵFactoryTarget.Injectable }); }
744
+ static { thisprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalCustomNavigationClient }); }
745
+ }
746
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MsalCustomNavigationClient, decorators: [{
747
+ type: Injectable
748
+ }], ctorParameters: () => [{ type: MsalService }, { type: i4.Router }, { type: i3.Location }] });
743
749
 
744
- /*
745
- * Copyright (c) Microsoft Corporation. All rights reserved.
746
- * Licensed under the MIT License.
747
- */
748
- /**
749
- * @packageDocumentation
750
- * @module @azure/msal-angular
750
+ /*
751
+ * Copyright (c) Microsoft Corporation. All rights reserved.
752
+ * Licensed under the MIT License.
753
+ */
754
+ /**
755
+ * @packageDocumentation
756
+ * @module @azure/msal-angular
751
757
  */
752
758
 
753
- /**
754
- * Generated bundle index. Do not edit.
759
+ /**
760
+ * Generated bundle index. Do not edit.
755
761
  */
756
762
 
757
763
  export { MSAL_BROADCAST_CONFIG, MSAL_GUARD_CONFIG, MSAL_INSTANCE, MSAL_INTERCEPTOR_CONFIG, MsalBroadcastService, MsalCustomNavigationClient, MsalGuard, MsalInterceptor, MsalModule, MsalRedirectComponent, MsalService, version };