@bravobit/bb-foundation 0.51.7 → 0.52.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/auth/lib/auth.interceptor.d.ts +5 -3
- package/auth/lib/auth.session.d.ts +7 -0
- package/auth/lib/interfaces/config.interface.d.ts +2 -0
- package/elements/lib/elements.interfaces.d.ts +1 -0
- package/elements/lib/file-picker/file-picker.component.d.ts +3 -1
- package/elements/lib/multi-file-control/multi-file-control.component.d.ts +6 -6
- package/fesm2022/bravobit-bb-foundation-auth.mjs +90 -59
- package/fesm2022/bravobit-bb-foundation-auth.mjs.map +1 -1
- package/fesm2022/bravobit-bb-foundation-elements.mjs +34 -22
- package/fesm2022/bravobit-bb-foundation-elements.mjs.map +1 -1
- package/localize/lib/transforms/interpolate.transform.d.ts +1 -1
- package/localize/lib/transforms/plural.transform.d.ts +1 -1
- package/localize/lib/transforms/reference.transform.d.ts +1 -1
- package/package.json +9 -9
|
@@ -7,12 +7,14 @@ export declare class AuthInterceptor implements HttpInterceptor {
|
|
|
7
7
|
private readonly _authHeaderString;
|
|
8
8
|
private readonly _authScheme;
|
|
9
9
|
isRefreshing: boolean;
|
|
10
|
-
refreshingAccessToken$: BehaviorSubject<
|
|
10
|
+
refreshingAccessToken$: BehaviorSubject<boolean>;
|
|
11
11
|
intercept(request: HttpRequest<unknown>, next: HttpHandler): import("rxjs").Observable<import("@angular/common/http").HttpEvent<any>>;
|
|
12
|
+
private modifyRequest;
|
|
13
|
+
private handleBrowserStorageRequest;
|
|
14
|
+
private handleHttpOnlyCookieRequest;
|
|
12
15
|
private handle401Error;
|
|
13
16
|
private logoutUser;
|
|
14
|
-
private
|
|
15
|
-
private addAuthorizationHeader;
|
|
17
|
+
private getAccessTokenFromSession;
|
|
16
18
|
static ɵfac: i0.ɵɵFactoryDeclaration<AuthInterceptor, never>;
|
|
17
19
|
static ɵprov: i0.ɵɵInjectableDeclaration<AuthInterceptor>;
|
|
18
20
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StorageStrategy } from '@bravobit/bb-foundation/storage';
|
|
2
|
+
import { AuthStrategy } from './interfaces/config.interface';
|
|
2
3
|
import { AuthToken } from './interfaces/token.interface';
|
|
3
4
|
export declare class AuthSession {
|
|
4
5
|
private readonly _jwt;
|
|
@@ -6,6 +7,7 @@ export declare class AuthSession {
|
|
|
6
7
|
private readonly _accessTokenStorageKey;
|
|
7
8
|
private readonly _refreshTokenStorageKey;
|
|
8
9
|
private readonly _userStorageKey;
|
|
10
|
+
private readonly _strategy;
|
|
9
11
|
private _accessTokenString;
|
|
10
12
|
private _refreshTokenString;
|
|
11
13
|
private _accessTokenPayload;
|
|
@@ -15,8 +17,13 @@ export declare class AuthSession {
|
|
|
15
17
|
constructor(options?: {
|
|
16
18
|
id?: string;
|
|
17
19
|
storage?: StorageStrategy;
|
|
20
|
+
strategy?: AuthStrategy;
|
|
18
21
|
});
|
|
19
22
|
get snapshot(): {
|
|
23
|
+
user: any;
|
|
24
|
+
accessToken?: undefined;
|
|
25
|
+
refreshToken?: undefined;
|
|
26
|
+
} | {
|
|
20
27
|
user: any;
|
|
21
28
|
accessToken: string;
|
|
22
29
|
refreshToken: string;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
|
|
2
2
|
import { InjectionToken } from '@angular/core';
|
|
3
|
+
export type AuthStrategy = 'httpOnlyCookie' | 'browserStorage';
|
|
3
4
|
export interface AuthConfig {
|
|
4
5
|
applicationId: string;
|
|
6
|
+
strategy: AuthStrategy;
|
|
5
7
|
http?: {
|
|
6
8
|
scheme?: string;
|
|
7
9
|
header?: string;
|
|
@@ -3,12 +3,13 @@ import { ControlValueAccessor, FormControl } from '@angular/forms';
|
|
|
3
3
|
import { BehaviorSubject } from 'rxjs';
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
5
|
export declare class BbFilePicker implements ControlValueAccessor {
|
|
6
|
+
private readonly _config?;
|
|
6
7
|
readonly labelId: string;
|
|
7
8
|
fileInput: ElementRef<HTMLInputElement>;
|
|
8
9
|
extraTemplate: TemplateRef<any>;
|
|
9
10
|
label: string | TemplateRef<any> | null;
|
|
10
11
|
hint: string | TemplateRef<any> | null;
|
|
11
|
-
accept: string
|
|
12
|
+
accept: string;
|
|
12
13
|
showImages: boolean;
|
|
13
14
|
grouped: boolean;
|
|
14
15
|
required: boolean;
|
|
@@ -39,6 +40,7 @@ export declare class BbFilePicker implements ControlValueAccessor {
|
|
|
39
40
|
};
|
|
40
41
|
saveFile(files: File[]): void;
|
|
41
42
|
private getFilesFromEvent;
|
|
43
|
+
private getAcceptString;
|
|
42
44
|
static ɵfac: i0.ɵɵFactoryDeclaration<BbFilePicker, never>;
|
|
43
45
|
static ɵcmp: i0.ɵɵComponentDeclaration<BbFilePicker, "bb-file-picker", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "showImages": { "alias": "showImages"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "hideErrors": { "alias": "hideErrors"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "valueChange": "valueChange"; }, ["extraTemplate"], never, true, never>;
|
|
44
46
|
static ngAcceptInputType_grouped: unknown;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ElementRef, EventEmitter, TemplateRef } from '@angular/core';
|
|
2
2
|
import { ControlValueAccessor, FormControl } from '@angular/forms';
|
|
3
|
-
import { Files } from '@bravobit/bb-foundation';
|
|
4
3
|
import * as i0 from "@angular/core";
|
|
5
4
|
export declare class BbMultiFileControl implements ControlValueAccessor {
|
|
6
|
-
private _files;
|
|
7
|
-
private _changeDetectorRef;
|
|
5
|
+
private readonly _files;
|
|
6
|
+
private readonly _changeDetectorRef;
|
|
7
|
+
private readonly _config?;
|
|
8
8
|
readonly labelId: string;
|
|
9
9
|
fileInput: ElementRef<HTMLInputElement>;
|
|
10
10
|
label: string | TemplateRef<any> | null;
|
|
11
11
|
hint: string | TemplateRef<any> | null;
|
|
12
|
-
accept: string
|
|
12
|
+
accept: string;
|
|
13
13
|
grouped: boolean;
|
|
14
14
|
required: boolean;
|
|
15
15
|
disabled: boolean;
|
|
@@ -28,7 +28,6 @@ export declare class BbMultiFileControl implements ControlValueAccessor {
|
|
|
28
28
|
error: boolean;
|
|
29
29
|
onTouchedCallback: () => void;
|
|
30
30
|
onChangeCallback: (_: File[] | null) => void;
|
|
31
|
-
constructor(_files: Files, _changeDetectorRef: ChangeDetectorRef);
|
|
32
31
|
get showList(): boolean;
|
|
33
32
|
downloadFile(file: File): void;
|
|
34
33
|
openFileDialog(): void;
|
|
@@ -47,6 +46,7 @@ export declare class BbMultiFileControl implements ControlValueAccessor {
|
|
|
47
46
|
};
|
|
48
47
|
addFiles(files: File[]): void;
|
|
49
48
|
private isFileLike;
|
|
49
|
+
private getAcceptString;
|
|
50
50
|
static ɵfac: i0.ɵɵFactoryDeclaration<BbMultiFileControl, never>;
|
|
51
51
|
static ɵcmp: i0.ɵɵComponentDeclaration<BbMultiFileControl, "bb-multi-file-control", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "hideErrors": { "alias": "hideErrors"; "required": false; }; "items": { "alias": "items"; "required": false; }; }, { "delete": "delete"; }, never, never, true, never>;
|
|
52
52
|
static ngAcceptInputType_grouped: unknown;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, inject, Injector, TransferState, makeStateKey, Injectable, Directive, Input, provideAppInitializer, makeEnvironmentProviders, NgModule } from '@angular/core';
|
|
3
|
-
import { HttpContextToken, HttpClient, HttpContext, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
3
|
+
import { HttpContextToken, HttpClient, HttpHeaders, HttpContext, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
4
4
|
import { shareReplay, tap, map, distinctUntilChanged, catchError, filter, take, switchMap, finalize } from 'rxjs/operators';
|
|
5
5
|
import { firstValueFrom, BehaviorSubject, of, Subscription, first, throwError } from 'rxjs';
|
|
6
6
|
import { Storage, StorageOption } from '@bravobit/bb-foundation/storage';
|
|
@@ -138,6 +138,7 @@ class AuthSession {
|
|
|
138
138
|
_accessTokenStorageKey;
|
|
139
139
|
_refreshTokenStorageKey;
|
|
140
140
|
_userStorageKey;
|
|
141
|
+
_strategy;
|
|
141
142
|
// Token strings.
|
|
142
143
|
_accessTokenString = null;
|
|
143
144
|
_refreshTokenString = null;
|
|
@@ -156,10 +157,14 @@ class AuthSession {
|
|
|
156
157
|
this._userStorageKey = this.generateKey(applicationId, 'au_usr');
|
|
157
158
|
// Setting up the storage.
|
|
158
159
|
this._storage = options?.storage ?? null;
|
|
160
|
+
this._strategy = options?.strategy ?? null;
|
|
159
161
|
// Init methods.
|
|
160
162
|
this.restoreFromStorage();
|
|
161
163
|
}
|
|
162
164
|
get snapshot() {
|
|
165
|
+
if (this._strategy === 'httpOnlyCookie') {
|
|
166
|
+
return { user: this._user$.getValue() };
|
|
167
|
+
}
|
|
163
168
|
return {
|
|
164
169
|
user: this._user$.getValue(),
|
|
165
170
|
accessToken: this.accessToken,
|
|
@@ -183,9 +188,12 @@ class AuthSession {
|
|
|
183
188
|
return this._refreshTokenPayload ?? null;
|
|
184
189
|
}
|
|
185
190
|
authenticated() {
|
|
186
|
-
return this.
|
|
191
|
+
return !!this.snapshot?.user;
|
|
187
192
|
}
|
|
188
193
|
setTokens(accessToken, refreshToken, persist = true) {
|
|
194
|
+
if (this._strategy === 'httpOnlyCookie') {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
189
197
|
this.setAccessToken(accessToken);
|
|
190
198
|
this.setRefreshToken(refreshToken);
|
|
191
199
|
if (persist) {
|
|
@@ -206,20 +214,22 @@ class AuthSession {
|
|
|
206
214
|
if (!this._storage) {
|
|
207
215
|
return;
|
|
208
216
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
if (this._strategy === 'browserStorage') {
|
|
218
|
+
// Set the access token.
|
|
219
|
+
const accessToken = this._storage.get(this._accessTokenStorageKey);
|
|
220
|
+
this.setAccessToken(accessToken);
|
|
221
|
+
// Set the refresh token.
|
|
222
|
+
const refreshToken = this._storage.get(this._refreshTokenStorageKey);
|
|
223
|
+
this.setRefreshToken(refreshToken);
|
|
224
|
+
}
|
|
215
225
|
// Set the user if we have any correct token payloads.
|
|
216
|
-
if (this._accessTokenPayload || this._refreshTokenPayload) {
|
|
226
|
+
if ((this._accessTokenPayload || this._refreshTokenPayload) || this._strategy === 'httpOnlyCookie') {
|
|
217
227
|
const user = this._storage.get(this._userStorageKey);
|
|
218
228
|
this._user$.next(user ?? null); // Note: just settings here instead of setUser() because of syncing to the storage.
|
|
219
229
|
}
|
|
220
230
|
}
|
|
221
231
|
persistTokensInStorage() {
|
|
222
|
-
if (!this._storage) {
|
|
232
|
+
if (!this._storage || this._strategy === 'httpOnlyCookie') {
|
|
223
233
|
return;
|
|
224
234
|
}
|
|
225
235
|
// Set the access token if completely valid.
|
|
@@ -263,15 +273,15 @@ class AuthSession {
|
|
|
263
273
|
this._refreshTokenString = value ?? null;
|
|
264
274
|
this._refreshTokenPayload = this._jwt.decode(this._refreshTokenString);
|
|
265
275
|
}
|
|
266
|
-
generateKey
|
|
276
|
+
generateKey(applicationId, key) {
|
|
267
277
|
return [applicationId, key].join('_');
|
|
268
|
-
}
|
|
269
|
-
isTokenValid
|
|
278
|
+
}
|
|
279
|
+
isTokenValid(token) {
|
|
270
280
|
if (!token) {
|
|
271
281
|
return false;
|
|
272
282
|
}
|
|
273
283
|
return token?.expiresAt?.getTime() > Date.now();
|
|
274
|
-
}
|
|
284
|
+
}
|
|
275
285
|
}
|
|
276
286
|
|
|
277
287
|
class Auth {
|
|
@@ -299,7 +309,8 @@ class Auth {
|
|
|
299
309
|
// Starting the new session.
|
|
300
310
|
this.session = new AuthSession({
|
|
301
311
|
id: this._config?.applicationId,
|
|
302
|
-
storage: storageStrategy
|
|
312
|
+
storage: storageStrategy,
|
|
313
|
+
strategy: this._config?.strategy
|
|
303
314
|
});
|
|
304
315
|
this.user = this.session.user;
|
|
305
316
|
}
|
|
@@ -318,15 +329,16 @@ class Auth {
|
|
|
318
329
|
const user = this._state?.get(this._authStateKey, null) ?? null;
|
|
319
330
|
return this.session.setUser(user);
|
|
320
331
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
this._state
|
|
332
|
+
if (this._config?.strategy === 'browserStorage') {
|
|
333
|
+
// Try to fetch the user from the server.
|
|
334
|
+
const user$ = this.me();
|
|
335
|
+
const user = await firstValueFrom(user$, { defaultValue: null });
|
|
336
|
+
// Set the state if exists.
|
|
337
|
+
if (this._state) {
|
|
338
|
+
this._state?.set(this._authStateKey, user ?? null);
|
|
339
|
+
}
|
|
340
|
+
this.session.setUser(user);
|
|
327
341
|
}
|
|
328
|
-
// Save the user in the storage and handle auto refreshing.
|
|
329
|
-
this.session.setUser(user);
|
|
330
342
|
this.handleAutoRefreshing();
|
|
331
343
|
}
|
|
332
344
|
me() {
|
|
@@ -365,10 +377,8 @@ class Auth {
|
|
|
365
377
|
}
|
|
366
378
|
async resendVerifyCode(verifyToken) {
|
|
367
379
|
const url = this.getUrl('auth/resend');
|
|
368
|
-
const result$ = this._httpClient.post(url, {
|
|
369
|
-
|
|
370
|
-
});
|
|
371
|
-
return firstValueFrom(result$);
|
|
380
|
+
const result$ = this._httpClient.post(url, { verify_token: verifyToken });
|
|
381
|
+
return await firstValueFrom(result$);
|
|
372
382
|
}
|
|
373
383
|
async register(data, options) {
|
|
374
384
|
// Execute API call.
|
|
@@ -388,30 +398,36 @@ class Auth {
|
|
|
388
398
|
// Note: We do this because else we try to invalidate
|
|
389
399
|
// an "undefined" refresh token.
|
|
390
400
|
const refreshToken = this.session.refreshToken;
|
|
391
|
-
if (!refreshToken) {
|
|
401
|
+
if (!refreshToken && this._config?.strategy === 'browserStorage') {
|
|
392
402
|
return this.session.clear();
|
|
393
403
|
}
|
|
394
|
-
// We do have a refresh token, so try to
|
|
395
|
-
//
|
|
404
|
+
// We do have a refresh token, so try to invalidate it in the backend.
|
|
405
|
+
// or we are httpOnlyCookie authenticated.
|
|
396
406
|
try {
|
|
397
407
|
const url = this.getUrl('auth/logout');
|
|
398
408
|
const headerName = this._config?.http?.header ?? 'Authorization';
|
|
409
|
+
const headers = new HttpHeaders({
|
|
410
|
+
[headerName]: refreshToken
|
|
411
|
+
});
|
|
399
412
|
const observable$ = this._httpClient.get(url, {
|
|
400
|
-
|
|
413
|
+
...(this._config?.strategy === 'browserStorage' ? { headers } : {}),
|
|
414
|
+
...(this._config?.strategy === 'httpOnlyCookie' ? { withCredentials: true } : {})
|
|
401
415
|
});
|
|
402
416
|
firstValueFrom(observable$).then(_ => _).catch(_ => _);
|
|
403
417
|
}
|
|
404
418
|
catch {
|
|
405
419
|
// Do nothing because the tokens will be deleted anyways from the session.
|
|
406
420
|
}
|
|
407
|
-
|
|
408
|
-
|
|
421
|
+
finally {
|
|
422
|
+
// Delete the tokens from the session.
|
|
423
|
+
this.session.clear();
|
|
424
|
+
}
|
|
409
425
|
}
|
|
410
426
|
refresh() {
|
|
411
427
|
// If the refresh token does
|
|
412
428
|
// not exist just return an observable of null.
|
|
413
429
|
const refreshToken = this.session.refreshToken;
|
|
414
|
-
if (!refreshToken) {
|
|
430
|
+
if (!refreshToken && this._config?.strategy === 'browserStorage') {
|
|
415
431
|
return of(null);
|
|
416
432
|
}
|
|
417
433
|
// Perform the refresh call.
|
|
@@ -419,8 +435,12 @@ class Auth {
|
|
|
419
435
|
const scheme = this._config?.http?.scheme ?? 'Bearer';
|
|
420
436
|
const url = this.getUrl('auth/refresh');
|
|
421
437
|
const context = new HttpContext().set(USE_AUTHORIZATION, false);
|
|
438
|
+
const headers = new HttpHeaders({
|
|
439
|
+
[headerName]: `${scheme} ${refreshToken}`
|
|
440
|
+
});
|
|
422
441
|
return this._httpClient.get(url, {
|
|
423
|
-
|
|
442
|
+
...(this._config?.strategy === 'browserStorage' ? { headers } : {}),
|
|
443
|
+
...(this._config?.strategy === 'httpOnlyCookie' ? { withCredentials: true } : {}),
|
|
424
444
|
context: context
|
|
425
445
|
}).pipe(tap(({ token, refresh_token }) => this.setTokens(token, refresh_token)), map(({ token }) => token));
|
|
426
446
|
}
|
|
@@ -461,7 +481,7 @@ class Auth {
|
|
|
461
481
|
}
|
|
462
482
|
handleAutoRefreshing() {
|
|
463
483
|
const shouldAutoRefresh = this._config?.autoRefresh ?? false;
|
|
464
|
-
if (!shouldAutoRefresh) {
|
|
484
|
+
if (!shouldAutoRefresh || this._config?.strategy === 'httpOnlyCookie') {
|
|
465
485
|
return;
|
|
466
486
|
}
|
|
467
487
|
const expiresAt = this.session.refreshTokenPayload?.expiresAt ?? null;
|
|
@@ -708,15 +728,14 @@ class AuthInterceptor {
|
|
|
708
728
|
_authScheme = this._config?.http?.scheme ?? 'Bearer';
|
|
709
729
|
// Data.
|
|
710
730
|
isRefreshing = false;
|
|
711
|
-
refreshingAccessToken$ = new BehaviorSubject(
|
|
731
|
+
refreshingAccessToken$ = new BehaviorSubject(false);
|
|
712
732
|
intercept(request, next) {
|
|
713
733
|
// 1. Check if the user wants to use the authorization for this request.
|
|
714
734
|
if (!request.context.get(USE_AUTHORIZATION)) {
|
|
715
735
|
return next.handle(request);
|
|
716
736
|
}
|
|
717
737
|
// 2. Compose the new request.
|
|
718
|
-
const
|
|
719
|
-
const newRequest = this.addAuthorizationHeader(request, accessToken);
|
|
738
|
+
const newRequest = this.modifyRequest(request);
|
|
720
739
|
// 3. Handle all errors.
|
|
721
740
|
return next.handle(newRequest).pipe(catchError(error => {
|
|
722
741
|
// Handle the HTTP401 error.
|
|
@@ -727,20 +746,42 @@ class AuthInterceptor {
|
|
|
727
746
|
return throwError(() => error);
|
|
728
747
|
}));
|
|
729
748
|
}
|
|
749
|
+
modifyRequest(request) {
|
|
750
|
+
switch (this._config?.strategy) {
|
|
751
|
+
case 'browserStorage':
|
|
752
|
+
return this.handleBrowserStorageRequest(request);
|
|
753
|
+
case 'httpOnlyCookie':
|
|
754
|
+
return this.handleHttpOnlyCookieRequest(request);
|
|
755
|
+
default:
|
|
756
|
+
throw new Error(`invalid auth strategy "${this._config?.strategy}"`);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
handleBrowserStorageRequest(request) {
|
|
760
|
+
const accessToken = this.getAccessTokenFromSession(request);
|
|
761
|
+
if (!accessToken) {
|
|
762
|
+
return request.clone({ headers: request.headers.delete(this._authHeaderString) });
|
|
763
|
+
}
|
|
764
|
+
return request.clone({
|
|
765
|
+
setHeaders: { [this._authHeaderString]: `${this._authScheme} ${accessToken}` }
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
handleHttpOnlyCookieRequest(request) {
|
|
769
|
+
return request.clone({ withCredentials: true });
|
|
770
|
+
}
|
|
730
771
|
handle401Error(request, next) {
|
|
731
772
|
// If already refreshing wait for the refresh token to complete.
|
|
732
773
|
if (this.isRefreshing) {
|
|
733
|
-
return this.refreshingAccessToken$.pipe(filter(accessToken => accessToken !==
|
|
774
|
+
return this.refreshingAccessToken$.pipe(filter(accessToken => accessToken !== false), take(1), switchMap(() => next.handle(this.modifyRequest(request))));
|
|
734
775
|
}
|
|
735
776
|
// Set the refreshing to true.
|
|
736
777
|
this.isRefreshing = true;
|
|
737
|
-
this.refreshingAccessToken$.next(
|
|
778
|
+
this.refreshingAccessToken$.next(false);
|
|
738
779
|
return this._auth.refresh().pipe(switchMap(newAccessToken => {
|
|
739
|
-
if (!newAccessToken) {
|
|
780
|
+
if (!newAccessToken && this._config?.strategy === 'browserStorage') {
|
|
740
781
|
return throwError(() => new Error('No refresh token was available.'));
|
|
741
782
|
}
|
|
742
|
-
this.refreshingAccessToken$.next(
|
|
743
|
-
return next.handle(this.
|
|
783
|
+
this.refreshingAccessToken$.next(true);
|
|
784
|
+
return next.handle(this.modifyRequest(request));
|
|
744
785
|
}), catchError(() => this.logoutUser()), finalize(() => this.isRefreshing = false));
|
|
745
786
|
}
|
|
746
787
|
logoutUser() {
|
|
@@ -749,27 +790,14 @@ class AuthInterceptor {
|
|
|
749
790
|
// Return null as data.
|
|
750
791
|
return of(null);
|
|
751
792
|
}
|
|
752
|
-
|
|
793
|
+
getAccessTokenFromSession(request) {
|
|
753
794
|
// Get the token based on header.
|
|
754
795
|
if (request.headers.has(this._authHeaderString)) {
|
|
755
796
|
return request.headers.get(this._authHeaderString);
|
|
756
797
|
}
|
|
757
798
|
// Return the default access token.
|
|
758
799
|
return this._auth.session.accessToken;
|
|
759
|
-
}
|
|
760
|
-
addAuthorizationHeader = (request, accessToken = null) => {
|
|
761
|
-
// Remove auth header when we do not have
|
|
762
|
-
// an access token.
|
|
763
|
-
if (!accessToken) {
|
|
764
|
-
return request.clone({
|
|
765
|
-
headers: request.headers.delete(this._authHeaderString)
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
// Add the auth header to the request.
|
|
769
|
-
return request.clone({
|
|
770
|
-
setHeaders: { [this._authHeaderString]: `${this._authScheme} ${accessToken}` }
|
|
771
|
-
});
|
|
772
|
-
};
|
|
800
|
+
}
|
|
773
801
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AuthInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
774
802
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.6", ngImport: i0, type: AuthInterceptor });
|
|
775
803
|
}
|
|
@@ -783,6 +811,9 @@ function provideAuthConfig(config) {
|
|
|
783
811
|
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
|
|
784
812
|
provideAppInitializer(() => inject(Auth).initialize())
|
|
785
813
|
];
|
|
814
|
+
if (config?.strategy === 'httpOnlyCookie' && !config?.bootstrap) {
|
|
815
|
+
throw new Error('the "bootstrap" option must be enabled when using strategy=httpOnlyCookie');
|
|
816
|
+
}
|
|
786
817
|
if (config?.interceptActing) {
|
|
787
818
|
providers.push({ provide: HTTP_INTERCEPTORS, useClass: ActingInterceptor, multi: true });
|
|
788
819
|
}
|