mod-portal-v2/app/composables/useAuth.js
2026-08-03 05:39:08 +02:00

220 lines
No EOL
4.9 KiB
JavaScript

import { ref } from 'vue'
const userToken = ref(null)
const refreshToken = ref(null)
const userProfile = ref(null)
const isAuthenticated = ref(false)
const isInitialized = ref(false)
let sessionPollTimer = null
const getStoredRefreshToken = () => {
if (refreshToken.value) {
return refreshToken.value
}
if (import.meta.client) {
return localStorage.getItem('keycloak_refresh_token')
}
return null
}
export const useAuth = () => {
const fetchUserProfile = async () => {
if (!userToken.value) return
try {
const profile = await $fetch('/api/user/profile', {
headers: {
Authorization: `Bearer ${userToken.value}`
}
})
userProfile.value = profile
} catch (err) {
console.error('Failed to fetch user profile:', err)
}
}
const setSession = (data) => {
userToken.value = data.access_token
if (data.refresh_token) {
refreshToken.value = data.refresh_token
if (import.meta.client) {
localStorage.setItem('keycloak_refresh_token', data.refresh_token)
}
}
isAuthenticated.value = true
}
const clearSession = () => {
stopLiveSessionPolling()
userToken.value = null
refreshToken.value = null
userProfile.value = null
isAuthenticated.value = false
if (import.meta.client) {
localStorage.removeItem('keycloak_refresh_token')
}
}
const exchangeCodeForToken = async (code) => {
try {
const data = await $fetch('/api/auth/token', {
method: 'POST',
body: {
code,
redirectUri: `${window.location.origin}/oauth`
}
})
setSession(data)
window.history.replaceState({}, document.title, window.location.pathname)
await fetchUserProfile()
startLiveSessionPolling()
return { success: true, isFirstLogin: data.isFirstLogin }
} catch (error) {
console.error('Code exchange failed:', error)
clearSession()
return { success: false, isFirstLogin: false }
} finally {
isInitialized.value = true
}
}
const silentRefresh = async () => {
const storedRefreshToken = getStoredRefreshToken()
if (!storedRefreshToken) {
clearSession()
isInitialized.value = true
return false
}
try {
const data = await $fetch('/api/auth/refresh', {
method: 'POST',
body: { refreshToken: storedRefreshToken }
})
setSession(data)
await fetchUserProfile()
startLiveSessionPolling()
return true
} catch (error) {
console.warn('Silent refresh failed:', error)
clearSession()
return false
} finally {
isInitialized.value = true
}
}
const verifySession = async () => {
if (!userToken.value) {
return await silentRefresh()
}
try {
const res = await $fetch('/api/auth/check-session', {
method: 'POST',
body: { token: userToken.value }
})
if (res.active) {
isAuthenticated.value = true
if (!userProfile.value) {
await fetchUserProfile()
}
return true
} else {
return await silentRefresh()
}
} catch (e) {
return await silentRefresh()
} finally {
isInitialized.value = true
}
}
const initializeAuth = async ({ code, redirectTo = '/oauth', replace = false } = {}) => {
if (code) {
const result = await exchangeCodeForToken(code)
if (!result.success) {
await navigateTo(redirectTo, { replace })
return false
}
return true
}
if (isAuthenticated.value) {
const valid = await verifySession()
if (!valid) {
await navigateTo(redirectTo, { replace })
return false
}
return true
}
const success = await silentRefresh()
if (!success) {
await navigateTo(redirectTo, { replace })
return false
}
return true
}
const startLiveSessionPolling = () => {
if (import.meta.server) return
stopLiveSessionPolling()
sessionPollTimer = setInterval(async () => {
if (isAuthenticated.value) {
const valid = await verifySession()
if (!valid) {
handleLocalLogout()
}
}
}, 5000)
}
const stopLiveSessionPolling = () => {
if (sessionPollTimer) {
clearInterval(sessionPollTimer)
sessionPollTimer = null
}
}
const handleLocalLogout = () => {
clearSession()
isInitialized.value = true
navigateTo('/oauth')
}
const logout = async () => {
try {
await $fetch('/api/auth/logout', {
method: 'POST',
body: { refreshToken: refreshToken.value }
})
} catch (e) {
console.warn('Server logout failed:', e)
} finally {
handleLocalLogout()
}
}
return {
userToken,
userProfile,
isAuthenticated,
isInitialized,
exchangeCodeForToken,
initializeAuth,
silentRefresh,
verifySession,
fetchUserProfile,
logout
}
}