177 lines
4.5 KiB
TypeScript
177 lines
4.5 KiB
TypeScript
import {
|
|
signInWithEmailAndPassword,
|
|
signInWithPopup,
|
|
GoogleAuthProvider,
|
|
signOut as firebaseSignOut,
|
|
onAuthStateChanged,
|
|
getAuth
|
|
} from 'firebase/auth'
|
|
import { getApps, initializeApp } from 'firebase/app'
|
|
import type { User } from 'firebase/auth'
|
|
|
|
export const useAuth = () => {
|
|
const user = ref<User | null>(null)
|
|
const isLoading = ref(true)
|
|
const error = ref<string | null>(null)
|
|
|
|
const config = useRuntimeConfig()
|
|
|
|
// Initialize Firebase if not already initialized
|
|
const initializeFirebase = async () => {
|
|
if (process.client && getApps().length === 0) {
|
|
console.log('Initializing Firebase with config:')
|
|
const firebaseConfig = {
|
|
apiKey: config.public.firebaseApiKey,
|
|
authDomain: config.public.firebaseAuthDomain,
|
|
projectId: config.public.firebaseProjectId,
|
|
storageBucket: config.public.firebaseStorageBucket,
|
|
messagingSenderId: config.public.firebaseMessagingSenderId,
|
|
appId: config.public.firebaseAppId,
|
|
...(config.public.firebaseMeasurementId
|
|
? { measurementId: config.public.firebaseMeasurementId }
|
|
: {})
|
|
}
|
|
await initializeApp(firebaseConfig)
|
|
}
|
|
}
|
|
|
|
// Get auth instance directly
|
|
const getAuthInstance = () => {
|
|
if (process.client) {
|
|
initializeFirebase()
|
|
return getAuth()
|
|
}
|
|
return null
|
|
}
|
|
|
|
// Initialize auth state listener
|
|
const initAuth = () => {
|
|
if (process.client) {
|
|
try {
|
|
const auth = getAuthInstance()
|
|
if (auth) {
|
|
onAuthStateChanged(auth, (firebaseUser) => {
|
|
user.value = firebaseUser
|
|
isLoading.value = false
|
|
})
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to initialize auth:', err)
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sign in with email and password
|
|
const signInWithEmail = async (email: string, password: string) => {
|
|
try {
|
|
error.value = null
|
|
isLoading.value = true
|
|
|
|
const auth = getAuthInstance()
|
|
if (!auth) {
|
|
throw new Error('Firebase not initialized')
|
|
}
|
|
|
|
const userCredential = await signInWithEmailAndPassword(auth, email, password)
|
|
const idToken = await userCredential.user.getIdToken()
|
|
|
|
try {
|
|
await authenticateWithBackend(idToken)
|
|
} catch (backendErr) {
|
|
console.warn('[useAuth] Backend authentication failed after email login:', backendErr)
|
|
}
|
|
|
|
return userCredential.user
|
|
} catch (err: any) {
|
|
error.value = err.message
|
|
throw err
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
// Sign in with Google
|
|
const signInWithGoogle = async () => {
|
|
try {
|
|
error.value = null
|
|
isLoading.value = true
|
|
|
|
const auth = getAuthInstance()
|
|
if (!auth) {
|
|
throw new Error('Firebase not initialized')
|
|
}
|
|
|
|
const provider = new GoogleAuthProvider()
|
|
const userCredential = await signInWithPopup(auth, provider)
|
|
const idToken = await userCredential.user.getIdToken()
|
|
|
|
try {
|
|
await authenticateWithBackend(idToken)
|
|
} catch (backendErr) {
|
|
console.warn('[useAuth] Backend authentication failed after Google login:', backendErr)
|
|
}
|
|
|
|
return userCredential.user
|
|
} catch (err: any) {
|
|
error.value = err.message
|
|
throw err
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
// Authenticate with backend
|
|
const authenticateWithBackend = async (idToken: string) => {
|
|
try {
|
|
const response = await $fetch('/auth/login', {
|
|
baseURL: config.public.backendUrl,
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: {
|
|
idToken
|
|
}
|
|
})
|
|
|
|
return response
|
|
} catch (err) {
|
|
console.error('Backend authentication failed:', err)
|
|
throw err
|
|
}
|
|
}
|
|
|
|
// Sign out
|
|
const signOut = async () => {
|
|
try {
|
|
const auth = getAuthInstance()
|
|
if (!auth) {
|
|
throw new Error('Firebase not initialized')
|
|
}
|
|
|
|
await firebaseSignOut(auth)
|
|
user.value = null
|
|
} catch (err: any) {
|
|
error.value = err.message
|
|
throw err
|
|
}
|
|
}
|
|
|
|
// Get current user's ID token
|
|
const getIdToken = async () => {
|
|
if (!user.value) return null
|
|
return await user.value.getIdToken()
|
|
}
|
|
|
|
return {
|
|
user: readonly(user),
|
|
isLoading: readonly(isLoading),
|
|
error: readonly(error),
|
|
initAuth,
|
|
signInWithEmail,
|
|
signInWithGoogle,
|
|
signOut,
|
|
getIdToken
|
|
}
|
|
} |