Adds access token refreshing.

This commit is contained in:
2025-04-17 01:43:28 -04:00
parent 9d2a00a928
commit c19e2eb493
2 changed files with 62 additions and 8 deletions

View File

@@ -19,6 +19,34 @@ export function useClient() {
api.interceptors.request.use(requestInterceptor);
// Add response interceptor for token refresh
api.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// If error is 401 and we haven't tried to refresh the token yet
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
// Attempt to refresh the token
await authStore.refresh();
// Retry the original request with the new token
originalRequest.headers["Authorization"] = `Bearer ${authStore.accessToken}`;
return api(originalRequest);
} catch (refreshError) {
// If refresh fails, logout the user
await authStore.logout();
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
return api;
}

View File

@@ -13,6 +13,17 @@ function getClaimsFromToken(token) {
}
}
function isTokenExpired(token) {
if (!token) return true;
const claims = getClaimsFromToken(token);
if (!claims) return true;
// Check if token will expire in the next 5 minutes
const expirationTime = claims.exp * 1000; // Convert to milliseconds
const currentTime = Date.now();
return currentTime >= expirationTime - 5 * 60 * 1000; // 5 minutes before expiration
}
export const useAuthStore = defineStore(
'auth',
() => {
@@ -22,7 +33,7 @@ export const useAuthStore = defineStore(
const accessToken = useSessionStorage('auth-accessToken', undefined)
const refreshToken = useSessionStorage('auth-refreshToken', undefined)
const isAuthenticated = computed(() => !!accessToken.value)
const isAuthenticated = computed(() => !!accessToken.value && !isTokenExpired(accessToken.value))
const userId = computed(() => {
const claims = getClaimsFromToken(accessToken.value)
@@ -96,20 +107,33 @@ export const useAuthStore = defineStore(
}
async function refresh() {
if (!refreshToken.value) {
throw new Error('No refresh token available');
}
try {
const response = await clientApi.post(
'api/users/refresh',
{
refreshToken: refreshToken
refreshToken: refreshToken.value
});
updateTokens({
accessToken: response.accessToken,
refreshToken: refreshToken
})
accessToken: response.data.accessToken,
refreshToken: response.data.refreshToken
});
return true;
} catch (error) {
console.error(error)
cleanTokens()
console.error('Token refresh failed:', error);
cleanTokens();
throw error;
}
}
// Function to check if token needs refresh
async function ensureValidToken() {
if (isTokenExpired(accessToken.value)) {
await refresh();
}
}
@@ -121,6 +145,8 @@ export const useAuthStore = defineStore(
login,
loginWithGoogle,
loginWithFacebook,
logout
logout,
refresh,
ensureValidToken
}
})