/** * Shared Auth Store Factory * * Creates a Pinia auth store that can be used by any ROA2WEB application. * Each app passes its own apiService instance configured with the correct baseURL. * * Usage: * import { createAuthStore } from '@shared/frontend/stores/auth'; * import { apiService } from '../services/api'; * export const useAuthStore = createAuthStore(apiService); */ import { defineStore } from "pinia"; import { ref, computed } from "vue"; /** * Factory function to create an auth store with the provided API service * @param {Object} apiService - Axios instance configured for the app's API * @returns {Function} Pinia store definition */ export function createAuthStore(apiService) { return defineStore("auth", () => { // State const accessToken = ref(localStorage.getItem("access_token")); const refreshToken = ref(localStorage.getItem("refresh_token")); const user = ref(JSON.parse(localStorage.getItem("user") || "null")); const isLoading = ref(false); const error = ref(null); // Getters const isAuthenticated = computed(() => !!accessToken.value); const currentUser = computed(() => user.value); // Actions const login = async (credentials) => { isLoading.value = true; error.value = null; try { const response = await apiService.post("/auth/login", { username: credentials.username, password: credentials.password, }); const { access_token, refresh_token, user: userData } = response.data; accessToken.value = access_token; refreshToken.value = refresh_token; user.value = userData; localStorage.setItem("access_token", access_token); localStorage.setItem("refresh_token", refresh_token); localStorage.setItem("user", JSON.stringify(userData)); apiService.defaults.headers.common["Authorization"] = `Bearer ${access_token}`; return { success: true }; } catch (err) { error.value = err.response?.data?.detail || "Login failed"; return { success: false, error: error.value }; } finally { isLoading.value = false; } }; const logout = () => { accessToken.value = null; refreshToken.value = null; user.value = null; error.value = null; localStorage.removeItem("access_token"); localStorage.removeItem("refresh_token"); localStorage.removeItem("user"); delete apiService.defaults.headers.common["Authorization"]; }; const refreshAccessToken = async () => { if (!refreshToken.value) { logout(); return false; } try { const response = await apiService.post("/auth/refresh", { refresh_token: refreshToken.value, }); const { access_token } = response.data; accessToken.value = access_token; localStorage.setItem("access_token", access_token); apiService.defaults.headers.common["Authorization"] = `Bearer ${access_token}`; return true; } catch (err) { console.error("Token refresh failed:", err); logout(); return false; } }; const initializeAuth = () => { if (accessToken.value) { apiService.defaults.headers.common["Authorization"] = `Bearer ${accessToken.value}`; } }; const clearError = () => { error.value = null; }; // Initialize on store creation initializeAuth(); return { // State accessToken, refreshToken, user, isLoading, error, // Getters isAuthenticated, currentUser, // Actions login, logout, refreshAccessToken, initializeAuth, clearError, }; }); }