import { betterAuth } from 'better-auth'; import { hash as argon2Hash, verify as argon2Verify } from '@node-rs/argon2'; import { kyselyAdapter } from '@better-auth/kysely-adapter'; import { Kysely, PostgresDialect } from 'kysely'; import { Pool } from 'pg'; import { sendEmail, verificationEmailHtml, resetPasswordEmailHtml } from './email'; const db = new Kysely({ dialect: new PostgresDialect({ pool: new Pool({ connectionString: process.env.DATABASE_URL || 'postgresql://labwise:labwise_dev_pw@localhost:5432/labwise_db', }), }), }); export const auth = betterAuth({ database: kyselyAdapter(db, { type: 'postgres' }), baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3001', secret: process.env.BETTER_AUTH_SECRET || 'dev-secret-change-in-production-min32chars!!', rateLimit: { enabled: false, // TODO: re-enable in production }, emailAndPassword: { enabled: true, requireEmailVerification: true, password: { hash: (password) => argon2Hash(password, { memoryCost: 65536, timeCost: 3, parallelism: 4, algorithm: 2 }), verify: ({ hash, password }) => argon2Verify(hash, password), }, sendResetPassword: async ({ user, url }) => { await sendEmail({ to: user.email, subject: 'Reset your LabWise password', html: resetPasswordEmailHtml(url), }); }, }, emailVerification: { sendVerificationEmail: async ({ user, url }) => { await sendEmail({ to: user.email, subject: 'Verify your LabWise email', html: verificationEmailHtml(url), }); }, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID || '', clientSecret: process.env.GOOGLE_CLIENT_SECRET || '', }, }, trustedOrigins: [ 'http://localhost:5173', 'https://labwise.wahwa.com', // iOS native app callback — allows Better Auth to honour the // https://labwise.wahwa.com/api/ios-callback callbackURL 'labwise://', ], });