Interceptor with firebase authentication
Asked Answered
P

3

7

I am having issues with my Angular 6 Interceptor. I have migrated the code from Angular 5.x to 6.0. and rxjs 5.x to 6.x. When I try to create a new user account, the request seems to be called twice. I know this because I log the error to the console. I have noticed that I get this duplication when I try to get the Id token from firebase auth, See code snippet below.

intercept (request: HttpRequest<any>, next: HttpHandler): observable<HttpEvent<any>> {
return this.auth.getIdToken().pipe(
    mergeMap((token: any) => {
      if (token) {
        request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
      }

      return next.handle(request).pipe(
        tap((event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {

          }
        }, (err: any) => {
          if (err instanceof HttpErrorResponse) {
            if ((err.status === 401) || (err.status === 403)) {
             this.router.navigate([WellknownRoutesConstants.SIGN_IN], { queryParams: { returnUrl: this.router.routerState.snapshot.url }});
            }
          }
        })
    );

  }));

}

getIdToken (): Observable<any> {
  return ngFireAuth.authState.pipe(
    tap((user) => {
      if (user) {
        return observableOf(user.getIdToken());
      } else {
        return observableOf;
      }
    }),
    catchError(observableOf)
  );
}
Parotid answered 27/6, 2018 at 2:26 Comment(2)
I've got same problem too.... did you find an answer for this?Fractional
I still don't have a solution yet.Parotid
G
10

Grant's answer is good, but there is a problem.

If the user logs out, the auth.idToken Observable emits a value because the token value changes to null. The request object remains unchanged (but still initialised), and so the HTTP request is repeated.

I used take(1) to take only the first value emitted by the auth.idToken Observable. I also changed to switchMap (see take):

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

   return this.auth.idToken.pipe(
      take(1), // <-------------- Only emit the first value!

      switchMap((token: any) => {
        if (token) {
          request = request.clone({
            setHeaders: { Authorization: `Bearer ${token}` }
          });
        }
        return next.handle(request);
      })

    );
}
Garcon answered 12/2, 2020 at 21:12 Comment(4)
unable to edit - as "edit queue is full". code doesn't compile in existing form. you need to change the , after take(1), to a ;Kleeman
@pokkie Thanks. It didn't need a ; but you were right that it was incorrect. take should have been outside of the switchMapGarcon
This MUST be the answer!Smile
Still works like a charm in Angular 11.1.2 and @angular/fire 6.1.4.Ondrej
J
6

This works for me since upgrading to Angular 6 / RxJS 6. Here's my interceptor:

import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

@Injectable()

export class TokenInterceptor implements HttpInterceptor {

  constructor(
    private auth: AngularFireAuth
  ) {
    console.log('token interceptor constructor');
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.auth.idToken.pipe(
      mergeMap((token: any) => {
        console.log(token);
        if (token) {
          request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
        }

        return next.handle(request);

    }));
  }
}
Jahdai answered 19/10, 2018 at 20:11 Comment(0)
E
0

It is not possible to intercept AngularFire calls using an Angular interceptor. AngularFire uses the Firebase SDK, which uses WebSockets to communicate with the Firebase backend. WebSocket calls cannot be intercepted by an HTTP interceptor.

One way to handle errors in AngularFire calls is to use the catchError operator in the observable chain. You can do this within the component or service where you are making the AngularFire call.

Alternatively, you could create a service that wraps the AngularFire calls and handles errors within that service. This way, you can centralize the error-handling logic in one place.

If you want to handle errors globally, you can create a custom error handler service that can be injected into the root component of your application. This error handler service can listen for errors that are thrown throughout the application and handle them as needed.

You can also use Cloud Functions to create a global error-handling mechanism for your Firebase backend. Cloud Functions allow you to run code in response to events in the Firebase ecosystem, including errors that occur in the Firebase backend.

Extinctive answered 24/12, 2022 at 19:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.