handle Refresh token - Angular interceptor

PHOTO EMBED

Mon Feb 27 2023 11:37:37 GMT+0000 (Coordinated Universal Time)

Saved by @mtommasi

import { catchError, EMPTY, Observable, switchMap, throwError } from 'rxjs';
import { AuthenticationService } from '../authentication.service';
import { UserService } from '../user.service';

@Injectable({
  providedIn: 'root',
})
export class AuthInterceptorService implements HttpInterceptor {
  constructor(private injector: Injector) {}
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    //this request should handle request if token is expired:
    //use a flag like "retry" if i should retry

    const reqClone = req.clone({ headers: req.headers.delete('skip', 'true') });

    return next.handle(reqClone).pipe(
      catchError((err) => {
        if (err.status === 401) {
          return this.handleRefreshToken(req, next);
        }
        return EMPTY;
      })
    );
  }

  handleRefreshToken(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const authService = this.injector.get(AuthenticationService); // approfondisci sta cosa
    return authService.refresh().pipe(
      switchMap((resp) => {
        return next.handle(req); // ripeto la richiesta con il sessiontoken fresco
      })
    );
  }
}

import { Injectable } from '@angular/core';
import {
  BehaviorSubject,
  catchError,
  EMPTY,
  filter,
  map,
  shareReplay,
  tap,
} from 'rxjs';
import { HttpClient } from '@angular/common/http';

import { IUser, IUserSignup } from '../models/user/user';
import { environment } from 'src/environments/environment';
import { LoginRequest } from '../models/login/login.request';
import { LoginResponse } from '../models/login/login.response';

const anonimous_USER: IUser = {
  email: '',
  username: '',
  id: '',
  roles: [],
};

@Injectable({
  providedIn: 'root',
})
export class AuthenticationService {
  private BASE = environment.base;
  private SIGNUP_URL = `${this.BASE}${environment.signupURL}`;
  private LOGOUT_URL = `${this.BASE}${environment.logout}`;
  private LOGIN_URL = `${this.BASE}${environment.login}`;
  private USER_URL = `${this.BASE}${environment.user}`;
  private REFRESH_URL = `${this.BASE}${environment.refresh}`;

  private ADMIN_AS_USER_URL = `${this.BASE}${environment.admin}${environment.loginAsUser}`;
  private subject = new BehaviorSubject<IUser | undefined>(anonimous_USER);
  public user$ = this.subject.pipe(filter((user) => Boolean(user)));
  public isLoggedIn$ = this.user$.pipe(map((user) => Boolean(user?.id)));
  public isLoggedOut$ = this.isLoggedIn$.pipe(map((loggedIn) => !loggedIn));

  constructor(private http: HttpClient) {
    this.getUserSession().subscribe((user) => this.subject.next(user));
  }

  signup(user: IUserSignup) {
    return this.http
      .post<IUser>(this.SIGNUP_URL, user, {
        headers: { skip: 'true' },
      })
      .pipe(
        shareReplay(),
        tap((user) => {
          console.log(user);
          this.subject.next(user);
        })
      );
  }
  getUserSession() {
    return this.http
      .get<IUser | undefined>(this.USER_URL, {
        headers: { skip: 'true' },
      })
      .pipe(shareReplay());
  }

  logout() {
    return this.http
      .post(this.LOGOUT_URL, null, { headers: { skip: 'true' } })
      .pipe(
        shareReplay(),
        tap(() => {
          this.subject.next(anonimous_USER); // emetto un utente nullo
        })
      );
  }

  login(loginRequest: LoginRequest) {
    return this.http
      .post<LoginResponse>(this.LOGIN_URL, loginRequest, {
        headers: { skip: 'true' },
      })
      .pipe(
        shareReplay(),
        tap((user) => {
          this.subject.next(user);
        })
      );
  }

  loginAsUser(userEmail: string) {
    return this.http
      .post<LoginResponse>(
        this.ADMIN_AS_USER_URL,
        { email: userEmail },
        {
          headers: { skip: 'true' },
        }
      )
      .pipe(
        shareReplay(),
        tap((user) => {
          this.subject.next(user);
        })
      );
  }

  refresh() {
    const email = this.subject.value?.email;
    return this.http.post(this.REFRESH_URL, { email: email || '' }).pipe(
      tap({
        error: (err) => {
          console.log(err);
        },
      }),
      shareReplay(),
      catchError(() => {
        return EMPTY; // non voglio che fa nulla se c'è un errore
      })
    );
  }
}
content_copyCOPY