import { betterAuth } from "better-auth"; import { magicLink, twoFactor, admin } from "better-auth/plugins"; import { nextCookies } from "better-auth/next-js"; import { Pool } from "pg"; import { sendMagicLinkEmail } from "./services/email"; import { ac, adminRole, userRole, superAdminRole } from "./permissions"; // Create a PostgreSQL pool for Better Auth const pool = new Pool({ connectionString: process.env.DATABASE_URL, }); export const auth = betterAuth({ database: pool, appName: "Pulse", baseURL: process.env.BETTER_AUTH_URL, secret: process.env.BETTER_AUTH_SECRET, trustedOrigins: [ "http://localhost:3100", "https://pulse.wulfconsulting.cloud" ], // Email & Password disabled - using magic link and Microsoft OAuth only emailAndPassword: { enabled: false, }, // Session configuration session: { expiresIn: parseInt(process.env.SESSION_TIMEOUT_SECONDS || "86400"), updateAge: 60 * 60, // Update session every hour cookieCache: { enabled: true, maxAge: 5 * 60, // 5 minutes }, }, // Social providers socialProviders: { microsoft: { clientId: process.env.MICROSOFT_CLIENT_ID || "", clientSecret: process.env.MICROSOFT_CLIENT_SECRET || "", tenantId: process.env.MICROSOFT_TENANT_ID || "common", }, }, // Plugins plugins: [ // Magic link authentication magicLink({ sendMagicLink: async ({ email, url, token }) => { await sendMagicLinkEmail({ email, url, token }); }, expiresIn: 300, // 5 minutes }), // Two-factor authentication twoFactor({ issuer: "Pulse", }), // Admin plugin with RBAC admin({ ac, roles: { "super-admin": superAdminRole, admin: adminRole, user: userRole, }, }), // Next.js cookie handling - must be last nextCookies(), ], // Allow Microsoft OAuth to link to existing accounts created by admins account: { accountLinking: { enabled: true, trustedProviders: ["microsoft"], }, }, // User configuration user: { additionalFields: { role: { type: "string", defaultValue: "user", }, requires_setup: { type: "boolean", defaultValue: false, }, timezone: { type: "string", defaultValue: process.env.DEFAULT_TIMEZONE || "UTC", }, theme: { type: "string", defaultValue: "system", }, }, }, }); export type Session = typeof auth.$Infer.Session; export type User = typeof auth.$Infer.Session.user;