mirror of
https://github.com/opelly27/WinStudentGoalTracker.git
synced 2026-05-20 02:57:36 +00:00
token expiration ajustment for testing
This commit is contained in:
@@ -9,7 +9,16 @@ namespace WinStudentGoalTracker.Services;
|
|||||||
public class TokenService
|
public class TokenService
|
||||||
{
|
{
|
||||||
private readonly IConfiguration _config;
|
private readonly IConfiguration _config;
|
||||||
private readonly int _tokenExpiryInSeconds = 60 * 15; // 15 minutes
|
|
||||||
|
// Temporary lowered to 1 minute expiration to test front end auth management
|
||||||
|
// and see if we get any random logouts or if token refresh is working as intended.
|
||||||
|
private readonly int _tokenExpiryInSeconds = 60; // 1 minute
|
||||||
|
|
||||||
|
// This is for the temporary non program scoped token that is granted at login
|
||||||
|
// and is only used for the selection of a program.
|
||||||
|
|
||||||
|
// In theory we have a bug here if someone sits at the program selection screen for more
|
||||||
|
// Than 5 minutes, the program selection will fail and they will be logged out.
|
||||||
private readonly int _sessionTokenExpiryInSeconds = 60 * 5; // 5 minutes
|
private readonly int _sessionTokenExpiryInSeconds = 60 * 5; // 5 minutes
|
||||||
|
|
||||||
public TokenService(IConfiguration config)
|
public TokenService(IConfiguration config)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { computed, inject, Injectable, signal } from '@angular/core';
|
import { computed, inject, Injectable, signal } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { catchError, EMPTY, Observable, of, Subject, tap } from 'rxjs';
|
import { catchError, finalize, Observable, of, shareReplay, Subject, tap } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
AuthUser,
|
AuthUser,
|
||||||
LoginResponse,
|
LoginResponse,
|
||||||
@@ -64,6 +64,7 @@ export class Auth {
|
|||||||
readonly sessionExpired$ = new Subject<void>();
|
readonly sessionExpired$ = new Subject<void>();
|
||||||
|
|
||||||
private refreshTimer: ReturnType<typeof setTimeout> | null = null;
|
private refreshTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
private refreshInFlight$: Observable<ResponseResult<TokenRefreshResponse>> | null = null;
|
||||||
|
|
||||||
// --------------- Accessors ---------------
|
// --------------- Accessors ---------------
|
||||||
|
|
||||||
@@ -138,15 +139,17 @@ export class Auth {
|
|||||||
return of({ success: false, message: 'No refresh token.' });
|
return of({ success: false, message: 'No refresh token.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._isRefreshing()) {
|
// If a refresh is already in flight, share the same observable
|
||||||
return EMPTY;
|
// so all callers wait for the single refresh and only one
|
||||||
|
// refresh token rotation happens on the backend.
|
||||||
|
if (this.refreshInFlight$) {
|
||||||
|
return this.refreshInFlight$;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isRefreshing.set(true);
|
this._isRefreshing.set(true);
|
||||||
|
|
||||||
return this.api.refreshToken({ refreshToken: token }).pipe(
|
this.refreshInFlight$ = this.api.refreshToken({ refreshToken: token }).pipe(
|
||||||
tap((res) => {
|
tap((res) => {
|
||||||
this._isRefreshing.set(false);
|
|
||||||
if (res.success && res.data) {
|
if (res.success && res.data) {
|
||||||
this.storeTokens(res.data.jwt, res.data.newRefreshToken);
|
this.storeTokens(res.data.jwt, res.data.newRefreshToken);
|
||||||
this.scheduleRefresh(res.data.jwtExpiresIn);
|
this.scheduleRefresh(res.data.jwtExpiresIn);
|
||||||
@@ -155,11 +158,17 @@ export class Auth {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
this._isRefreshing.set(false);
|
|
||||||
this.forceLogout();
|
this.forceLogout();
|
||||||
return of({ success: false, message: 'Token refresh failed.' } as ResponseResult<TokenRefreshResponse>);
|
return of({ success: false, message: 'Token refresh failed.' } as ResponseResult<TokenRefreshResponse>);
|
||||||
}),
|
}),
|
||||||
|
finalize(() => {
|
||||||
|
this._isRefreshing.set(false);
|
||||||
|
this.refreshInFlight$ = null;
|
||||||
|
}),
|
||||||
|
shareReplay(1),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return this.refreshInFlight$;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------- Logout ---------------
|
// --------------- Logout ---------------
|
||||||
@@ -238,6 +247,7 @@ export class Auth {
|
|||||||
|
|
||||||
private clearState(): void {
|
private clearState(): void {
|
||||||
this.clearRefreshTimer();
|
this.clearRefreshTimer();
|
||||||
|
this.refreshInFlight$ = null;
|
||||||
localStorage.removeItem(STORAGE_KEYS.JWT);
|
localStorage.removeItem(STORAGE_KEYS.JWT);
|
||||||
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
|
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
|
||||||
localStorage.removeItem(STORAGE_KEYS.SESSION_TOKEN);
|
localStorage.removeItem(STORAGE_KEYS.SESSION_TOKEN);
|
||||||
|
|||||||
Reference in New Issue
Block a user