import { NextAuthOptions } from 'next-auth' import CredentialsProvider from 'next-auth/providers/credentials' import bcrypt from 'bcryptjs' export const authOptions: NextAuthOptions = { secret: process.env.NEXTAUTH_SECRET, providers: [ CredentialsProvider({ name: 'credentials', credentials: { username: { label: 'Username', type: 'text' }, password: { label: 'Password', type: 'password' }, }, async authorize(credentials) { if (!credentials?.username || !credentials?.password) return null const adminUsername = process.env.ADMIN_USERNAME let adminPasswordHash = process.env.ADMIN_PASSWORD_HASH if (!adminUsername || !adminPasswordHash) { throw new Error('Admin credentials not configured') } // Handle base64 encoded hash to avoid Next.js .env $ expansion issues if (adminPasswordHash.startsWith('JDJ') || (!adminPasswordHash.startsWith('$2') && !adminPasswordHash.startsWith('$2a'))) { try { const decoded = Buffer.from(adminPasswordHash, 'base64').toString('utf8') if (decoded.startsWith('$2')) { adminPasswordHash = decoded } } catch { // keep original if decoding fails } } if (credentials.username !== adminUsername) return null const isValid = await bcrypt.compare(credentials.password, adminPasswordHash) if (!isValid) return null return { id: '1', name: adminUsername, email: `${adminUsername}@configvault` } }, }), ], session: { strategy: 'jwt' }, pages: { signIn: '/login', }, callbacks: { async jwt({ token, user }) { if (user) token.id = user.id return token }, async session({ session, token }) { if (session.user) (session.user as any).id = token.id return session }, }, }