import { betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { admin, organization } from "better-auth/plugins"; import { nextCookies } from "better-auth/next-js"; import { prisma } from "@/lib/db"; import { sendEmail, emailLayout } from "@/lib/email"; const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"; const googleConfigured = !!(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET); export const auth = betterAuth({ appName: "PodcastYes", secret: process.env.BETTER_AUTH_SECRET, baseURL: process.env.BETTER_AUTH_URL ?? appUrl, database: prismaAdapter(prisma, { provider: "postgresql" }), emailAndPassword: { enabled: true, // Flip on once email delivery is verified in prod. requireEmailVerification: false, minPasswordLength: 8, async sendResetPassword({ user, url }) { await sendEmail({ to: user.email, subject: "Reset your PodcastYes password", html: emailLayout( "Reset your password", "Click the button below to choose a new password.", { label: "Reset password", url } ), text: `Reset your password: ${url}`, }); }, }, emailVerification: { sendOnSignUp: false, async sendVerificationEmail({ user, url }) { await sendEmail({ to: user.email, subject: "Verify your email for PodcastYes", html: emailLayout( "Confirm your email", "Confirm your email address to secure your account.", { label: "Verify email", url } ), text: `Verify your email: ${url}`, }); }, }, socialProviders: googleConfigured ? { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }, } : undefined, session: { expiresIn: 60 * 60 * 24 * 30, // 30 days updateAge: 60 * 60 * 24, // refresh daily cookieCache: { enabled: true, maxAge: 5 * 60 }, }, account: { accountLinking: { enabled: true, trustedProviders: ["google"] }, }, plugins: [ admin({ defaultRole: "user", adminRoles: ["admin"] }), organization({ teams: { enabled: true, maximumTeams: 1 }, // Agency seat cap is enforced in app logic against the subscription's seat count. membershipLimit: 5, }), // Must remain last: lets Server Actions / route handlers set auth cookies. nextCookies(), ], }); export type Session = typeof auth.$Infer.Session;