Skip to content

Commit d72604d

Browse files
Update interceptor to use AuthService and wait for SDK to finish loading (#376)
1 parent 0a4e9f1 commit d72604d

File tree

2 files changed

+86
-4
lines changed

2 files changed

+86
-4
lines changed

projects/auth0-angular/src/lib/auth.interceptor.spec.ts

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {
1313
AuthClientConfig,
1414
HttpInterceptorConfig,
1515
} from './auth.config';
16-
import { throwError } from 'rxjs';
16+
import { BehaviorSubject, Subject, throwError } from 'rxjs';
1717
import { Auth0Client } from '@auth0/auth0-spa-js';
1818
import { Auth0ClientService } from './auth.client';
1919
import { AuthState } from './auth.state';
20+
import { AuthService } from './auth.service';
2021

2122
// NOTE: Read Async testing: https://github.com/angular/angular/issues/25733#issuecomment-636154553
2223

@@ -38,6 +39,8 @@ describe('The Auth HTTP Interceptor', () => {
3839
let req: TestRequest;
3940
let authState: AuthState;
4041
const testData: Data = { message: 'Hello, world' };
42+
let authService: AuthService;
43+
let isLoading$: Subject<boolean>;
4144

4245
const assertAuthorizedApiCallTo = async (
4346
url: string,
@@ -65,6 +68,7 @@ describe('The Auth HTTP Interceptor', () => {
6568
let config: Partial<AuthConfig>;
6669

6770
beforeEach(() => {
71+
isLoading$ = new BehaviorSubject<boolean>(false);
6872
req = undefined as any;
6973

7074
auth0Client = new Auth0Client({
@@ -74,7 +78,7 @@ describe('The Auth HTTP Interceptor', () => {
7478

7579
jest
7680
.spyOn(auth0Client, 'getTokenSilently')
77-
.mockResolvedValue('access-token');
81+
.mockImplementation(() => Promise.resolve('access-token'));
7882

7983
config = {
8084
httpInterceptor: {
@@ -133,12 +137,19 @@ describe('The Auth HTTP Interceptor', () => {
133137
provide: AuthClientConfig,
134138
useValue: { get: () => config },
135139
},
140+
{
141+
provide: AuthService,
142+
useValue: {
143+
isLoading$,
144+
},
145+
},
136146
],
137147
});
138148

139149
httpClient = TestBed.inject(HttpClient);
140150
httpTestingController = TestBed.inject(HttpTestingController);
141151
authState = TestBed.inject(AuthState);
152+
authService = TestBed.inject(AuthService);
142153

143154
jest.spyOn(authState, 'setError');
144155
});
@@ -168,6 +179,25 @@ describe('The Auth HTTP Interceptor', () => {
168179
});
169180

170181
describe('Requests that are configured using a primitive', () => {
182+
it('waits unil isLoading emits false', fakeAsync(async (
183+
done: () => void
184+
) => {
185+
const method = 'GET';
186+
const url = 'https://my-api.com/api/photos';
187+
188+
isLoading$.next(true);
189+
190+
httpClient.request(method, url).subscribe(done);
191+
flush();
192+
193+
httpTestingController.expectNone(url);
194+
195+
isLoading$.next(false);
196+
flush();
197+
198+
httpTestingController.expectOne(url);
199+
}));
200+
171201
it('attach the access token when the configuration uri is a string', fakeAsync(async (
172202
done: () => void
173203
) => {
@@ -210,6 +240,25 @@ describe('The Auth HTTP Interceptor', () => {
210240
});
211241

212242
describe('Requests that are configured using a complex object', () => {
243+
it('waits unil isLoading emits false', fakeAsync(async (
244+
done: () => void
245+
) => {
246+
const method = 'GET';
247+
const url = 'https://my-api.com/api/orders';
248+
249+
isLoading$.next(true);
250+
251+
httpClient.request(method, url).subscribe(done);
252+
flush();
253+
254+
httpTestingController.expectNone(url);
255+
256+
isLoading$.next(false);
257+
flush();
258+
259+
httpTestingController.expectOne(url);
260+
}));
261+
213262
it('attach the access token when the uri is configured using a string', fakeAsync(async (
214263
done: () => void
215264
) => {
@@ -316,6 +365,25 @@ describe('The Auth HTTP Interceptor', () => {
316365
});
317366

318367
describe('Requests that are configured using an uri matcher', () => {
368+
it('waits unil isLoading emits false', fakeAsync(async (
369+
done: () => void
370+
) => {
371+
const method = 'GET';
372+
const url = 'https://my-api.com/api/orders';
373+
374+
isLoading$.next(true);
375+
376+
httpClient.request(method, url).subscribe(done);
377+
flush();
378+
379+
httpTestingController.expectNone(url);
380+
381+
isLoading$.next(false);
382+
flush();
383+
384+
httpTestingController.expectOne(url);
385+
}));
386+
319387
it('attach the access token when the matcher returns true', fakeAsync(async (
320388
done: () => void
321389
) => {

projects/auth0-angular/src/lib/auth.interceptor.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,29 @@ import {
1919
switchMap,
2020
first,
2121
concatMap,
22-
pluck,
2322
catchError,
2423
tap,
24+
filter,
25+
mergeMap,
26+
mapTo,
27+
pluck,
2528
} from 'rxjs/operators';
2629
import { Auth0Client, GetTokenSilentlyOptions } from '@auth0/auth0-spa-js';
2730
import { Auth0ClientService } from './auth.client';
2831
import { AuthState } from './auth.state';
32+
import { AuthService } from './auth.service';
33+
34+
const waitUntil = <TSignal>(signal$: Observable<TSignal>) => <TSource>(
35+
source$: Observable<TSource>
36+
) => source$.pipe(mergeMap((value) => signal$.pipe(first(), mapTo(value))));
2937

3038
@Injectable()
3139
export class AuthHttpInterceptor implements HttpInterceptor {
3240
constructor(
3341
private configFactory: AuthClientConfig,
3442
@Inject(Auth0ClientService) private auth0Client: Auth0Client,
35-
private authState: AuthState
43+
private authState: AuthState,
44+
private authService: AuthService,
3645
) {}
3746

3847
intercept(
@@ -44,6 +53,10 @@ export class AuthHttpInterceptor implements HttpInterceptor {
4453
return next.handle(req);
4554
}
4655

56+
const isLoaded$ = this.authService.isLoading$.pipe(
57+
filter((isLoading) => !isLoading),
58+
);
59+
4760
return this.findMatchingRoute(req, config.httpInterceptor).pipe(
4861
concatMap((route) =>
4962
iif(
@@ -52,6 +65,7 @@ export class AuthHttpInterceptor implements HttpInterceptor {
5265
// If we have a matching route, call getTokenSilently and attach the token to the
5366
// outgoing request
5467
of(route).pipe(
68+
waitUntil(isLoaded$),
5569
pluck('tokenOptions'),
5670
concatMap<GetTokenSilentlyOptions, Observable<string>>((options) =>
5771
this.getAccessTokenSilently(options).pipe(

0 commit comments

Comments
 (0)