import {Injectable} from '@angular/core'; import {LoginService} from '@api'; import {CookieService} from 'ngx-cookie-service'; import {BehaviorSubject, Observable, throwError} from 'rxjs'; import {catchError, tap} from 'rxjs/operators'; import {MatSnackBar} from '@angular/material/snack-bar'; import {JwtHelperService} from '@auth0/angular-jwt'; @Injectable({ providedIn: 'root' }) export class AuthService { private isAuthenticatedSubject = new BehaviorSubject(false); public isAuthenticated$ = this.isAuthenticatedSubject.asObservable(); private userClaimsSubject = new BehaviorSubject(null); public userClaims$ = this.userClaimsSubject.asObservable(); constructor( private loginService: LoginService, private cookieService: CookieService, private snackBar: MatSnackBar, private jwtHelper: JwtHelperService ) { // Check if user is already logged in on service initialization this.checkAuthStatus(); } /** * Attempt to login with the provided code */ public login(code: string): Observable { return this.loginService.login(code).pipe( tap(jwt => { this.saveJwt(jwt); this.isAuthenticatedSubject.next(true); }), catchError(error => { this.snackBar.open('Login failed', '', {duration: 2000}); return throwError(() => error); }) ); } /** * Log the user out by removing the JWT */ public logout(): void { this.cookieService.delete('jwt', '/'); this.isAuthenticatedSubject.next(false); this.userClaimsSubject.next(null); } /** * Check if the user is authenticated */ public checkAuthStatus(): boolean { const jwt = this.getJwt(); if (jwt) { try { // Check if token is expired if (this.jwtHelper.isTokenExpired(jwt)) { this.logout(); return false; } const claims = this.extractJwtClaims(jwt); this.userClaimsSubject.next(claims); this.isAuthenticatedSubject.next(true); return true; } catch (e) { this.logout(); } } return false; } /** * Get the JWT from cookies */ public getJwt(): string | null { return this.cookieService.check('jwt') ? this.cookieService.get('jwt') : null; } /** * Save the JWT to cookies */ private saveJwt(jwt: string): void { this.cookieService.set('jwt', jwt, { path: '/', secure: true, sameSite: 'Strict' }); const claims = this.extractJwtClaims(jwt); this.userClaimsSubject.next(claims); } /** * Extract claims from JWT */ private extractJwtClaims(jwt: string): JwtClaims { return this.jwtHelper.decodeToken(jwt); } /** * Get user authorizations from claims */ public getUserAuthorizations(): string[] { const claims = this.userClaimsSubject.getValue(); return claims?.authorizations || []; } public hasAccess(authorization: string[]): boolean { return this.getUserAuthorizations().filter(entry => authorization.includes(entry)).length > 0; } }