brackt/app/lib/auth.server.ts
Chris Parsons d2282a263e Fix BetterAuth field mapping and add owner-prefixed team names
- Fix auth.server.ts: use camelCase Drizzle field names for BetterAuth
  adapter (was snake_case, causing user inserts to fail); add
  generateId: "uuid" so PostgreSQL UUID columns accept generated IDs
- Add prependOwnerToTeamName / stripOwnerFromTeamName utilities
- Invite join, league creation, and settings assign/remove all now
  manage the owner-prefix on team names atomically

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 08:31:16 -07:00

69 lines
2.1 KiB
TypeScript

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import bcrypt from "bcrypt";
import { Resend } from "resend";
import { db } from "~/server/db";
if (!process.env.BETTER_AUTH_SECRET) {
throw new Error("BETTER_AUTH_SECRET is required");
}
const resend = new Resend(process.env.RESEND_API_KEY);
const googleProvider = process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
? { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET } }
: {};
const discordProvider = process.env.DISCORD_CLIENT_ID && process.env.DISCORD_CLIENT_SECRET
? { discord: { clientId: process.env.DISCORD_CLIENT_ID, clientSecret: process.env.DISCORD_CLIENT_SECRET } }
: {};
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
usePlural: true,
}),
advanced: {
database: {
generateId: "uuid",
},
},
user: {
fields: {
name: "displayName",
image: "imageUrl",
},
additionalFields: {
firstName: { type: "string", required: false, fieldName: "firstName" },
lastName: { type: "string", required: false, fieldName: "lastName" },
username: { type: "string", required: false, fieldName: "username" },
isAdmin: { type: "boolean", defaultValue: false, fieldName: "isAdmin" },
},
},
emailAndPassword: {
enabled: true,
password: {
hash: (password: string) => bcrypt.hash(password, 10),
verify: ({ hash, password }: { hash: string; password: string }) =>
bcrypt.compare(password, hash),
},
sendResetPassword: async ({ user, url }) => {
await resend.emails.send({
from: "Brackt <noreply@brackt.com>",
to: user.email,
subject: "Reset your Brackt password",
html: `<p>Click the link below to reset your password. This link expires in 1 hour.</p><p><a href="${url}">${url}</a></p>`,
});
},
},
socialProviders: {
...googleProvider,
...discordProvider,
},
account: {
accountLinking: {
enabled: true,
trustedProviders: ["google", "discord"],
},
},
});