import { betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { getPrisma } from "./db"; import { loadSystemConfig } from "./system-config"; import { setCached, getCached, deleteCached, cacheKeys } from "./redis"; let authInstance: ReturnType | null = null; export async function getAuth() { if (authInstance) { return authInstance; } const prisma = await getPrisma(); const cfg = await loadSystemConfig(); if (!prisma) { throw new Error("Database not configured"); } const isDevelopment = process.env.NODE_ENV === "development"; const baseURL = process.env.APP_BASE_URL || (isDevelopment ? "http://localhost:3001" : "https://estate-platform.com"); authInstance = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql", }), secret: cfg.auth?.jwtSecret || process.env.BETTER_AUTH_SECRET || "default-secret-change-me", baseURL: baseURL, trustHost: true, // Disable origin validation in development ...(isDevelopment && { skipOriginValidation: true, }), csrfProtection: false, // Disable CSRF protection completely advanced: { useSecureCookies: !isDevelopment, // Allow non-secure cookies in development disableMultipleTabsWarning: isDevelopment, sessionTimeout: 86400 * 7, // 7 days defaultCookieMaxAge: 86400 * 7, // 7 days }, emailAndPassword: { enabled: true, autoSignUpDisabled: false, minPasswordLength: 8, maxPasswordLength: 20, requireEmailVerification: cfg.email?.enabled || false, }, socialProviders: { google: { clientId: cfg.oauth?.google?.clientId || process.env.GOOGLE_CLIENT_ID || "", clientSecret: cfg.oauth?.google?.clientSecret || process.env.GOOGLE_CLIENT_SECRET || "", }, github: { clientId: cfg.oauth?.github?.clientId || process.env.GITHUB_CLIENT_ID || "", clientSecret: cfg.oauth?.github?.clientSecret || process.env.GITHUB_CLIENT_SECRET || "", }, facebook: { clientId: cfg.oauth?.facebook?.clientId || process.env.FACEBOOK_CLIENT_ID || "", clientSecret: cfg.oauth?.facebook?.clientSecret || process.env.FACEBOOK_CLIENT_SECRET || "", }, discord: { clientId: cfg.oauth?.discord?.clientId || process.env.DISCORD_CLIENT_ID || "", clientSecret: cfg.oauth?.discord?.clientSecret || process.env.DISCORD_CLIENT_SECRET || "", }, }, }); return authInstance; } // Session caching helper export async function cacheSession(sessionId: string, sessionData: any) { try { await setCached(cacheKeys.session(sessionId), sessionData, 604800); // 7 days } catch (error) { console.error("[Auth] Error caching session:", error); } } export async function getCachedSession(sessionId: string) { try { return await getCached(cacheKeys.session(sessionId)); } catch (error) { console.error("[Auth] Error getting cached session:", error); return null; } } export async function invalidateSessionCache(sessionId: string) { try { await deleteCached(cacheKeys.session(sessionId)); } catch (error) { console.error("[Auth] Error invalidating session cache:", error); } } // User caching helper export async function cacheUser(userId: string, userData: any) { try { await setCached(cacheKeys.user(userId), userData, 3600); // 1 hour } catch (error) { console.error("[Auth] Error caching user:", error); } } export async function getCachedUser(userId: string) { try { return await getCached(cacheKeys.user(userId)); } catch (error) { console.error("[Auth] Error getting cached user:", error); return null; } } export async function invalidateUserCache(userId: string) { try { await deleteCached(cacheKeys.user(userId)); } catch (error) { console.error("[Auth] Error invalidating user cache:", error); } } // Re-export BetterAuth session types export type { Session } from "better-auth"; export type { User } from "better-auth";