2022-02-16

Angular - How to initialize auth interceptor before APP_INITIALIZER service is initialized?

I have an Angular application with an auth interceptor that adds a JWT to each request.

auth.interceptor.ts gets the user instance and JWT from the user.service as soon as it is available:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    currentUser: User;

    constructor(private userService: UserService) {
        this.userService.user$
            .subscribe(currentUser => this.currentUser = currentUser);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        if (this.currentUser && this.currentUser.token) {
            const requestWithAuthHeader = req.clone({
                headers: req.headers.set('authorization', 'Bearer ' + this.currentUser.token)
            });
            return next.handle(requestWithAuthHeader);

        }
    }
}

I have another service, that gets the user object from user.service, and sends an HTTP request as soon as user is available:

@Injectable({ providedIn: 'root' })
export class SettingsService {

    constructor(private http: HttpClient, private userService: UserService) {
        this.userService.user$.pipe(
            filter(user => !!user && !!user.token), // wait until user is not null
        ).subscribe(() => this.fetchAppSettingsFromServer()); // sends an Http request
    }
}

SettingsService is loaded very early in the app, using the APP_INITIALIZER in the app.module:

{ provide: APP_INITIALIZER, useFactory: () => () => null, deps: [SettingsService], multi: true },

This leads to a situaltion where SettingsService gets the user object early and sends an http request very quickly before the auth.interceptor has a chance to be initialized, and the result is an http request without an added JWT.

To solve this, I added a small delay in sending the request, to allow the auth.interceptor enough time to be initialized, and it works fine:

@Injectable({ providedIn: 'root' })
export class SettingsService {
    constructor(private http: HttpClient, private userService: UserService) {
        this.userService.user$.pipe(
            filter(user => !!user && !!user.token), // wait until user is not null
            delay(100) // wait until auth.interceptor is initialized
        ).subscribe(() => this.fetchAppSettings()); // must connect before app loads to support eaarly loading of data before component is diplayed
    }
    // ...
}

But this doesn't seem like the best solution, and there must be a more elegant way to do it. Any ideas how to make auth.interceptor get ready before SettingsService sends out a request?



from Recent Questions - Stack Overflow https://ift.tt/HwqVg7e
https://ift.tt/2seQpNE

No comments:

Post a Comment