import NextAuth from "next-auth"; import type { DefaultSession, NextAuthConfig } from "next-auth"; import Credentials from "next-auth/providers/credentials"; import GitHub from "next-auth/providers/github"; import Google from "next-auth/providers/google"; /** * Optional: `pnpm add @auth/drizzle-adapter` then wire DrizzleAdapter + session strategy "database". * Using JWT + Credentials/OAuth; `db` is loaded dynamically inside `authorize` (Node route handler only). * User lookup uses the postgres.js client from Drizzle (`db.$client`) so we avoid a direct `drizzle-orm` import in this app. */ declare module "next-auth" { interface Session { user: { id: string; } & DefaultSession["user"]; } } const providers: NextAuthConfig["providers"] = [ Credentials({ name: "Email", credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { const email = credentials?.email as string | undefined; const password = credentials?.password as string | undefined; if (!email?.trim() || !password) return null; const devPassword = process.env.AUTH_DEV_PASSWORD; if (!devPassword) { console.warn("[auth] AUTH_DEV_PASSWORD is not set; credentials sign-in disabled."); return null; } if (password !== devPassword) return null; const { db } = await import("@tasks/database/client"); const sql = (db as { $client: (t: TemplateStringsArray, ...v: unknown[]) => Promise }) .$client; const rows = (await sql` SELECT id, email, name, avatar_url AS "avatarUrl" FROM users WHERE lower(email) = lower(${email.trim()}) LIMIT 1 `) as { id: string; email: string; name: string | null; avatarUrl: string | null }[]; const user = rows[0]; if (!user) return null; return { id: user.id, email: user.email, name: user.name ?? undefined, image: user.avatarUrl ?? undefined, }; }, }), ]; if (process.env.AUTH_GITHUB_ID && process.env.AUTH_GITHUB_SECRET) { providers.push( GitHub({ clientId: process.env.AUTH_GITHUB_ID, clientSecret: process.env.AUTH_GITHUB_SECRET, }), ); } if (process.env.AUTH_GOOGLE_ID && process.env.AUTH_GOOGLE_SECRET) { providers.push( Google({ clientId: process.env.AUTH_GOOGLE_ID, clientSecret: process.env.AUTH_GOOGLE_SECRET, }), ); } export const { handlers, auth, signIn, signOut } = NextAuth({ session: { strategy: "jwt" }, pages: { signIn: "/sign-in", }, providers, callbacks: { async jwt({ token, user }) { if (user?.id) { token.id = user.id; } return token; }, async session({ session, token }) { if (session.user && token.id) { session.user.id = token.id as string; } return session; }, }, trustHost: true, });