// lib/auth.ts:27
export const auth = betterAuth({
baseURL: getAuthBaseUrl(),
database: drizzleAdapter(db, {
provider: "pg",
schema: { user, session, account, verification, workspace },
}),
emailAndPassword: {
enabled: true,
minPasswordLength: 8,
requireEmailVerification: true,
sendResetPassword: async ({ user: resetUser, url, token }) => {
const resetLink = `${baseUrl}/reset-password?token=${token}`;
await sendPasswordResetEmail(resetUser.email, resetUser.name, resetLink);
},
resetPasswordTokenExpiresIn: 60 * 60, // 1 hour
},
emailVerification: {
sendVerificationEmail: async ({ user: verifyUser, url }) => {
await sendVerificationEmail(verifyUser.email, verifyUser.name, url);
},
sendOnSignUp: true,
sendOnSignIn: true, // Resend verification on unverified sign-in attempts
autoSignInAfterVerification: true,
},
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days
updateAge: 60 * 60 * 24, // 1 day (refresh session if older than this)
},
plugins: [
admin({
impersonationSessionDuration: 60 * 60 * 24, // 1 day
}),
],
databaseHooks: {
user: {
create: {
after: async (createdUser) => {
// Auto-create workspace on signup
const slug = createdUser.email
.split("@")[0]
.toLowerCase()
.replace(/[^a-z0-9]/g, "-");
const workspaceId = nanoid();
await db.insert(workspace).values({
id: workspaceId,
name: `${createdUser.name}'s Workspace`,
slug: `${slug}-${workspaceId.slice(0, 6)}`,
});
await db
.update(user)
.set({ workspaceId, role: "owner" })
.where(eq(user.id, createdUser.id));
},
},
},
},
});