import {EventEmitter, Injectable} from '@angular/core'; import {HttpClient, HttpHeaders} from "@angular/common/http"; import {catchError, Observable, of, tap} from "rxjs"; import {TokenResponse} from "@api/v1/tokenResponse"; import ApiService from "@api/api.service"; export enum AvailableAuthenticationProvider { Bearer } export class AuthToken { accessToken: string; expiresIn: Date; authProvider: AvailableAuthenticationProvider; endpoint: string; constructor(accessToken: string, expiresIn: Date, authProvider: AvailableAuthenticationProvider, refreshEndpoint: string) { this.accessToken = accessToken; this.expiresIn = expiresIn; this.authProvider = authProvider; this.endpoint = refreshEndpoint; } static httpHeader(token: AuthToken): HttpHeaders { let header = new HttpHeaders(); if (token.authProvider === AvailableAuthenticationProvider.Bearer) header = header.set('Authorization', `Bearer ${token.accessToken}`); return header; } } @Injectable({ providedIn: 'root', }) export class AuthService { public expireTokenChange = new EventEmitter(); public tokenChangeError = new EventEmitter(); constructor(private http: HttpClient) { } public static setToken(token: TokenResponse, provider: AvailableAuthenticationProvider, refreshEndpoint: string) { localStorage.setItem(ApiService.tokenKey, JSON.stringify( new AuthToken(token.accessToken, token.expiresIn, provider, refreshEndpoint) )); } public static get tokenExpiresIn(): Date { const token = localStorage.getItem(ApiService.tokenKey); if (!token) return new Date(); const result = new Date((JSON.parse(token) as AuthToken).expiresIn); return result <= new Date() ? new Date() : result; } public refreshToken(): Observable { const token = localStorage.getItem(ApiService.tokenKey); if (!token) return of(); const authToken = JSON.parse(token) as AuthToken; switch (authToken.authProvider) { case AvailableAuthenticationProvider.Bearer: return this.http.get(authToken.endpoint, {withCredentials: true}) .pipe( catchError(error => { this.tokenChangeError.emit(); throw error; }), tap(response => { const newExpireDate = new Date(response.expiresIn); const oldExpireDate = new Date(authToken.expiresIn); if (newExpireDate.getTime() !== oldExpireDate.getTime()) { AuthService.setToken(response, AvailableAuthenticationProvider.Bearer, authToken.endpoint); this.expireTokenChange.emit(newExpireDate); } }) ); } } }