// Copied from https://github.com/atinux/nuxthub-better-auth import { defu } from 'defu' import { createAuthClient } from 'better-auth/client' import type { InferSessionFromClient, InferUserFromClient, ClientOptions } from 'better-auth/client' import { organizationClient, jwtClient } from 'better-auth/client/plugins' import type { RouteLocationRaw } from 'vue-router' interface RuntimeAuthConfig { redirectUserTo: RouteLocationRaw | string redirectGuestTo: RouteLocationRaw | string } const session = ref | null>(null) const user = ref | null>(null) const sessionFetching = import.meta.server ? ref(false) : ref(false) const jwt = ref(null) const organizations = ref< { id: string; name: string; createdAt: Date; slug: string; metadata?: any; logo?: string | null }[] >([]) const selectedOrganization = ref<{ id: string name: string createdAt: Date slug: string metadata?: any logo?: string | null } | null>(null) export function useAuth() { const url = useRequestURL() const headers = import.meta.server ? useRequestHeaders() : undefined const client = createAuthClient({ baseURL: url.origin, fetchOptions: { headers }, plugins: [organizationClient(), jwtClient()] }) const options = defu(useRuntimeConfig().public.auth as Partial, { redirectUserTo: '/', redirectGuestTo: '/login' }) async function fetchSession() { if (sessionFetching.value) { console.log('already fetching session') return } sessionFetching.value = true const { data } = await client.getSession({ fetchOptions: { headers } }) session.value = data?.session || null user.value = data?.user || null sessionFetching.value = false // Fetch JWT - workaround for not working extraction of JWT out of session (https://github.com/better-auth/better-auth/issues/1835) jwt.value = (await client.token()).data?.token ?? null // Fetch organization organizations.value = (await client.organization.list()).data ?? [] if (!selectedOrganization.value && organizations.value.length > 0) { selectedOrganization.value = organizations.value[0] } return data } watch( () => selectedOrganization.value, async (newValue) => { if (newValue) { await client.organization.setActive({ organizationId: newValue?.id }) } } ) if (import.meta.client) { client.$store.listen('$sessionSignal', async (signal) => { if (!signal) return await fetchSession() }) } async function signOut({ redirectTo }: { redirectTo?: RouteLocationRaw } = {}) { const res = await client.signOut() if (res.error) { console.error('Error signing out:', res.error) return res } session.value = null user.value = null if (redirectTo) { await navigateTo(redirectTo) } return res } return { session, user, loggedIn: computed(() => !!session.value), signIn: client.signIn, signUp: client.signUp, signOut, organization: client.organization, organizations, selectedOrganization, options, fetchSession, client, jwt } }