File size: 6,834 Bytes
e4ab6d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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<boolean>(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<any> {
    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<any> {
    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<boolean> {
    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);
          }
        }
      );
    }
  }


}