feat: Update authentication and profile components

This commit is contained in:
2025-04-22 15:39:53 -04:00
parent 3bb52e7555
commit 22867b5765
2 changed files with 176 additions and 116 deletions

View File

@@ -6,6 +6,7 @@ import {useSessionStorage} from "@vueuse/core";
import {jwtDecode} from "jwt-decode";
function getClaimsFromToken(token) {
if (!token) return null;
try {
return jwtDecode(token);
} catch (error) {
@@ -17,12 +18,15 @@ function getClaimsFromToken(token) {
function isTokenExpiringSoon(token) {
if (!token) return true;
const claims = getClaimsFromToken(token);
if (!claims) return true;
if (!claims || !claims.exp) 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
const fiveMinutesInMs = 5 * 60 * 1000;
// Return true if token is expired or will expire in the next 5 minutes
return currentTime >= expirationTime - fiveMinutesInMs;
}
export const useAuthStore = defineStore(
@@ -38,77 +42,121 @@ export const useAuthStore = defineStore(
const accessToken = useSessionStorage('auth-accessToken', undefined)
const refreshToken = useSessionStorage('auth-refreshToken', undefined)
// Cache for decoded claims using session storage with proper serialization
const tokenClaims = useSessionStorage('auth-tokenClaims', null, {
serializer: {
read: (v) => v ? JSON.parse(v) : null,
write: (v) => v ? JSON.stringify(v) : null
}
})
const isAuthenticated = computed(() => !!accessToken.value)
const userId = computed(() => {
const claims = getClaimsFromToken(accessToken.value)
return claims?.sub;
})
const userId = computed(() => tokenClaims.value?.sub)
function updateTokens(data) {
accessToken.value = data.accessToken
refreshToken.value = data.refreshToken
if (!data?.accessToken || !data?.refreshToken) {
throw new Error('Invalid token data');
}
accessToken.value = data.accessToken;
refreshToken.value = data.refreshToken;
// Update claims cache when we get new tokens
const claims = getClaimsFromToken(data.accessToken);
tokenClaims.value = claims;
}
function cleanTokens() {
updateTokens({
accessToken: undefined,
refreshToken: undefined,
})
accessToken.value = undefined;
refreshToken.value = undefined;
tokenClaims.value = null;
// Clear any other auth-related data if needed
}
async function logout() {
cleanTokens()
await router.push('/')
try {
// Optionally call logout endpoint if you have one
// await clientApi.post('api/users/logout');
} catch (error) {
console.error('Logout failed:', error);
} finally {
cleanTokens();
await router.push('/');
}
}
async function login(email, password) {
if (!email || !password) {
throw new Error('Email and password are required');
}
try {
const response = await clientApi.post(
'api/users/login',
{
email: email,
email: email.trim(),
password: password
})
updateTokens(response.data)
return true
});
if (!response.data?.accessToken || !response.data?.refreshToken) {
throw new Error('Invalid login response');
}
updateTokens(response.data);
return true;
} catch (error) {
console.error(error)
cleanTokens()
return false
console.error('Login failed:', error);
cleanTokens();
throw error;
}
}
async function loginWithGoogle(accessToken) {
if (!accessToken) {
throw new Error('Google access token is required');
}
try {
const response = await clientApi.post(
'api/users/login-with-google',
{
token: accessToken
})
updateTokens(response.data)
return true
});
if (!response.data?.accessToken || !response.data?.refreshToken) {
throw new Error('Invalid Google login response');
}
updateTokens(response.data);
return true;
} catch (error) {
console.error(error)
cleanTokens()
return false
console.error('Google login failed:', error);
cleanTokens();
throw error;
}
}
async function loginWithFacebook(authResponse) {
if (!authResponse?.accessToken) {
throw new Error('Facebook access token is required');
}
try {
const response = await clientApi.post(
'api/users/login-with-facebook',
{
token: authResponse.accessToken
})
updateTokens(response.data)
return true
});
if (!response.data?.accessToken || !response.data?.refreshToken) {
throw new Error('Invalid Facebook login response');
}
updateTokens(response.data);
return true;
} catch (error) {
console.error(error)
cleanTokens()
return false
console.error('Facebook login failed:', error);
cleanTokens();
throw error;
}
}
@@ -133,6 +181,10 @@ export const useAuthStore = defineStore(
refreshToken: refreshToken.value
});
if (!response.data?.accessToken || !response.data?.refreshToken) {
throw new Error('Invalid refresh response');
}
updateTokens({
accessToken: response.data.accessToken,
refreshToken: response.data.refreshToken