Encountering an issue with managing promises in Observables for Angular HTTP Interceptor

Currently, I am encountering the following situation:

I have developed an authentication service using Angular/Fire with Firebase authentication. The authentication service is expected to return the ID token through the idToken observable from Angular/Fire:

public getAuthenticationToken(): Observable<string | null> {
const auth = getAuth()

return idToken(auth).pipe(
  switchMap(token => {
      return of(token)
  })
)}

The HTTP Interceptor needs to extract the token from the authentication service and add it to the header if it exists:

@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {

  constructor(private userService: UserService) {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.userService.getAuthenticationToken().pipe(
      switchMap((token) => {
        const newRequest = request.clone()

        if(token) {
          newRequest.headers.set('Authorization', token);
        }
        return next.handle(newRequest)
      })
    )
  }
}

However, I am facing an issue where every request is sent out successfully the first time but fails to send subsequent requests. These requests are initiated by a feature service within an effect. Interestingly, removing the interceptor resolves the issue, allowing multiple requests to be sent as expected.

Here is an example effect:

SaveArticle$ = createEffect(() =>
    this.actions$.pipe(
      ofType(savedArticlesActions.saveArticle),
      concatMap((payload) =>
        this.articleService.saveArticle(payload).pipe(
          map((response) =>
            savedArticlesActions.saveArticleSuccess({
              article: response.article, message: "Article successfully saved"
            })
          ),
          catchError((error) => of(savedArticlesActions.saveArticleFailure(error)))
        )
      )
    )
  );

When I changed the map operator to switchMap in the above effect, the requests were sent multiple times along with the interceptor. However, reverting to another map operator still resulted in each request being sent only once.

My current setup includes:

  • Angular 16
  • RXJS 7.5

I acknowledge that there may be a crucial aspect I am overlooking, but I am unsure of what it could be.

Thank you for any assistance provided.

Answer №1

It seems like the function idToken() acts as an ongoing Observable with no end.

By using

this.userService.getAuthenticationToken()
in your request, you're causing the inner observable within the concatMap to never finish, even after receiving the initial response.

To resolve this, make sure to add first() within your interceptor to only wait for the initial token value.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.userService.getAuthenticationToken().pipe(
      first(),
      switchMap((token) => {
        const newRequest = request.clone()

        if(token) {
          newRequest.headers.set('Authorization', token);
        }
        return next.handle(newRequest)
      })
    )
  }

Following this approach will guarantee that the http call completes and enables concatMap to subscribe to the next value.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Introducing an extra 'pipe' in rxjs angular may result in generating errors

Encountering an unusual issue with Angular. The following code functions correctly: this.form.valueChanges .pipe( startWith(this.form.value), pairwise(), tap(() => console.log('aa')) ...

Tips for triggering the update of index.view when the Save command is triggered within an active dialog

When I try to save in an open dialog using the Save command, the parent index.view does not update. However, everything works fine when using the SaveAndClose command. This was tested on the Product object at https://github.com/alex-kukhtin/A2v10.Web.Sampl ...

Arranging information within the Ngb-Accordion

Welcome to the code snippet showcasing how to create an accordion in Angular: <ngb-accordion [closeOthers]="false" activeIds="0"> <ng-container class="card" *ngFor="let post of Posts"> <ngb-panel title="{{post.title}} - ...

Autoformatting files with ESLint on save

I'm encountering an issue where Visual Studio Code is saving my file in violation of the rules specified in my eslint configuration when using eslint and prettier for formatting. module.exports = { env: { browser: true, es2022: true, nod ...

[Heroku][Angular] Dealing with "Template parse errors" upon deploying my application

Encountered errors while deploying my application using "express" on Heroku: Uncaught Error: Template parse errors: Unexpected closing tag "button". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR ...

Fix React/Typescript issue: Exported variable conflicts with name from external module

I am encountering a perplexing issue when using React with Redux and Typescript. The error message I am receiving is unfamiliar to me, and I am unsure how to resolve it. The error states: Exported variable 'rootReducer' has or is using name ...

Configuring VS Code's "tasks.json" file to compile all .ts files can be done by following these steps

Apologies if this question has been asked before, but could someone please redirect me to the relevant thread if so. I am wondering if it is possible to set up VS Code's "tasks.json" to automatically compile all .ts files within a folder. Currently, I ...

Showing the child component as undefined in the view

Within my Angular application, I encountered an issue involving a parent component named DepotSelectionComponent and its child component SiteDetailsComponent. The problem arises when an event called moreDetails is emitted to the parent component, triggerin ...

Troubleshooting: Angular 2 View not reflecting changes after array push

I have encountered an issue with my two child components. They are both meant to share data from a json file that I load using the http.get/subscribe method. Oddly enough, when I try to push new data into the array, it doesn't seem to update in the vi ...

Generating TypeScript Type Definitions for dynamic usage

In my client server application, I use REST calls for communication. To avoid using the wrong types by mistake, I have defined all RestCalls in a common file (excerpt): type def<TConnection extends Connections> = // Authentication ...

Angular 13: SyntaxError Encountered: Token 'export' Not Recognized

After upgrading Angular from version 12 to 13, I encountered an error when running the app: "Uncaught SyntaxError: Unexpected token 'export'." Here are some additional details for context: In the angular.json configuration file, I had specified ...

Best practice in Angular 2: The difference between binding an object as a whole versus binding its individual

What is the best approach for a child component when dealing with object properties and change events? Example 1 <parent-component> <child-component [exampleInput]="object.val" (valueChanged)="updateObjectValue($event)"> ...

Sidenav selector unable to display Angular component

I'm facing a dilemma. I have the following code in my app.component.html file: <mat-sidenav-container class="sidenav-container"> <app-sidenav></app-sidenav> <mat-sidenav-content> <app-header></app-header> ...

Tips for accessing an AWS EC2 instance endpoint using HTTPS rather than HTTP

I am facing an issue with my Angular client (v14) trying to communicate with a Spring Boot application running on an AWS EC2 instance. The Angular app is hosted on Firebase and deployed under HTTPS. When attempting http calls in Angular using something lik ...

Angular2 ngIf can cause disruption in the styles of elements

In my Angular 2 app, I have integrated an MDL stepper element. It is placed inside a div container. However, when I add the *ngIf directive with a condition to this div, the stepper component breaks completely. Surprisingly, without the *ngIf directive, th ...

Utilize localStorage.getItem() in conjunction with TypeScript to retrieve stored data

Within my codebase, I have the following line: const allGarments = teeMeasuresAverages || JSON.parse(localStorage.getItem("teeMeasuresAverages")) || teeMeasuresAveragesLocal; Unexpectedly, Typescript triggers an alert with this message: Argument ...

Can you explain the distinction between ng test and ng e2e?

Concerned that someone might close my question, I struggled to find a satisfactory answer. Perhaps it's due to my limited knowledge in the Angular 2+ realm or maybe I misunderstood something. From what I gathered after dabbling in Hello World project ...

What could be the reason for the absence of the mandatory message while using the mat datepicker

Here is a template I am currently using: <input type="text" class="form-control" name="my_date" [matDatepicker]="myDatepicker" #myDate="ngModel" [(ngModel)]="myDateValue" id="my_date" required> &l ...

What is the purpose of a Typescript function that returns a function with a generic type?

I recently stumbled upon a perplexing piece of TypeScript code that revolves around the function componentControl. Despite my efforts, I find myself struggling to fully comprehend its purpose and functionality. componentControl: const componentControl: &l ...

The Firebase Authentication Emulator consistently presents authentic Google account suggestions

TL;DR I am facing an issue with the Firebase Auth Emulator suggesting real Google accounts instead of dummy accounts. DETAILED Setting up firebase providers: importProvidersFrom( provideAuth(() => { const auth = getAuth(); if (en ...