feat: Update authentication and profile components
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user