import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs/internal/Observable'; import { tap } from 'rxjs/operators'; import { catchError } from 'rxjs/operators'; import { throwError } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthenticationService { private apiUrl = 'http://127.0.0.1:5000'; // Your backend URL private loggedInSubject = new BehaviorSubject(this.isLoggedIn()); // BehaviorSubject to track login status constructor(private http: HttpClient) { // Change from 5 minutes to 30 seconds setInterval(() => this.checkAndRefreshToken(), 30 * 1000); // Every 30 seconds // Periodically check for token expiry and refresh it if necessary //setInterval(() => this.checkAndRefreshToken(), 5 * 60 * 1000); // Check every 5 minutes } // ✅ Login Method // ✅ Login Method (returns an Observable) login(username: string, password: string): Observable { const loginData = { username, password }; return this.http.post(`${this.apiUrl}/login`, loginData).pipe( tap((response: any) => { //const now = new Date(); // Store tokens in localStorage localStorage.setItem('access_token', response.access_token); localStorage.setItem('refresh_token', response.refresh_token); // Optionally store expiry time of the access token (2 minutes) const accessTokenExpiry = Date.now() + 2 * 60 * 1000; // 2 minutes expiration for access token localStorage.setItem('access_token_expiry', accessTokenExpiry.toString()); // Optionally store expiry time of the refresh token (5 minutes) const refreshTokenExpiry = Date.now() + 10 * 60 * 1000; // 5 minutes expiration for refresh token localStorage.setItem('refresh_token_expiry', refreshTokenExpiry.toString()); this.loggedInSubject.next(true); }), catchError(error => { // Handle error (token expiry / invalid login) if (error.status === 401 && error.error.message === 'Token has expired') { //alert('Your session has expired, please log in again.'); } return throwError(error); }) ); } logout(): Observable { const token = this.getToken(); console.log('🔑 Token at logout start:', token); this.removeToken(); // Remove token first this.loggedInSubject.next(false); if (!token) { console.warn('⚠️ No token found. Emitting success anyway.'); return new Observable(observer => { observer.next(true); observer.complete(); }); } const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`); console.log('📤 Sending logout request with headers:', headers); return this.http.post(`${this.apiUrl}/logout`, {}, { headers }).pipe( tap(() => { console.log('✅ Logout API request completed'); // This should now appear }), catchError((error) => { console.error('❌ Logout error in service:', error); return new Observable(observer => { observer.next(true); // Continue flow even on error observer.complete(); }); }) ); } // ✅ Get Token (to use for making authorized requests) getToken(): string | null { return localStorage.getItem('access_token'); } // ✅ Store Token storeToken(token: string): void { localStorage.setItem('access_token', token); console.log('Token stored:', token); // Log the token to confirm it's saved this.loggedInSubject.next(true); // Update login status } // ✅ Remove Token removeToken(): void { localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); localStorage.removeItem('access_token_expiry'); this.loggedInSubject.next(false); // Update login status } // ✅ Check if the user is logged in isLoggedIn(): boolean { return !!this.getToken(); } // ✅ Observable to track login status get isLoggedIn$(): Observable { return this.loggedInSubject.asObservable(); } checkAndRefreshToken() { const accessTokenExpiry = localStorage.getItem('access_token_expiry'); if (accessTokenExpiry && Date.now() >= (+accessTokenExpiry - 5000)) { // Refresh 5 seconds before expiry this.refreshAccessToken(); } } // Check token every 5 minutes // ✅ Refresh Access Token Method // ✅ Refresh Access Token Method //refreshAccessToken() { // const refreshToken = localStorage.getItem('refresh_token'); // if (refreshToken) { // this.http.post(`${this.apiUrl}/refresh`, { refresh_token: refreshToken }).subscribe((response: any) => { // // Store the new access token // localStorage.setItem('access_token', response.access_token); // // Optionally, update the expiry time of the new access token (2 minutes) // const newAccessTokenExpiry = Date.now() + 2 * 60 * 1000; // 2 minutes // localStorage.setItem('access_token_expiry', newAccessTokenExpiry.toString()); // alert('Your access token has been refreshed successfully!'); // }, error => { // console.log("Error refreshing token", error); // // Handle token refresh failure (e.g., log out the user) // this.logout(); // }); // } //} refreshAccessToken() { const refreshToken = localStorage.getItem('refresh_token'); if (refreshToken) { this.http.post(`${this.apiUrl}/refresh`, { refresh_token: refreshToken }).subscribe( (response: any) => { // Store the new access token localStorage.setItem('access_token', response.access_token); // Update expiry const newAccessTokenExpiry = Date.now() + 2 * 60 * 1000; // 2 minutes localStorage.setItem('access_token_expiry', newAccessTokenExpiry.toString()); //alert('Your access token has been refreshed successfully!'); }, error => { console.log("Error refreshing token", error); if ( error.status === 401 && (error.error.message === 'Refresh token has expired' || error.error.message === 'Invalid refresh token') ) { //alert('Your session has expired. Please log in again.'); // ✅ Remove tokens and redirect to login this.removeToken(); this.loggedInSubject.next(false); window.location.href = '/authentication'; // Adjust this if your login route is different } else { // Other errors can be handled differently console.error("Unexpected error:", error); } } ); } } }