====================
== alfr3dosv blog ==
====================

Implement an HttpInterceptor to add and refresh a token

The following HttpInterceptor will add the authorization header and in case of getting a 403

  • Will refresh the token and resubmit the original http petition
  • Block the following requests while trying to refresh the to
  • In case that the token cannot be refreshed it will redirect to the login page
// AuthService
export class AuthService {
    estaLogeado() {}
    cerrarSesion() {}
    refrescarToken() {}
}
// Interceptor
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
import { catchError, filter, finalize, switchMap, take, tap } from 'rxjs/operators';
import { AuthService } from './auth.service';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
    constructor(private authService: AuthService, private router: Router) { }

    private refreshTokenInProgress = false;
    private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(this.agregarToken(request)).pipe(
            catchError((error: any) => {
                console.error('error', error);
                if (request.url.includes('login') || error.status != 403) {
                    return throwError(error);
                } else if (request.url.includes('refresh-token')) {
                    this.refreshTokenInProgress = false;
                    this.authService.cerrarSesion();
                    this.router.navigate(['/login']);
                } else if (!this.refreshTokenInProgress) {
                    this.refreshTokenInProgress = true;
                    this.refreshTokenSubject.next(null);
                    // waiting
                    return this.authService.refrescarToken()
                        .pipe(
                            switchMap((token: string) => {
                                this.refreshTokenInProgress = false;
                                this.refreshTokenSubject.next(token);
                                return next.handle(this.addToken(request));
                            })
                        )        
                } else {
                    return this.refreshTokenSubject
                        .pipe(
                            filter(token => token != null),
                            take(1),
                            switchMap(token => {
                                return next.handle(this.addToken(request));
                            }),
                        );
                }
            })
        )
    }

    addToken(request) {
        if (!this.authService.estaLogeado()) {
            return request;
        };
        return request.clone({
            setHeaders: {
                Authorization: `Bearer ${localStorage['token']}`
            }
        });
    }
}