Files

61 lines
2.0 KiB
TypeScript
Raw Permalink Normal View History

/**
* Create (or promote) an admin user with a hashed email/password credential.
*
* Usage: npx tsx scripts/create-admin.ts <email> <password> [name]
*
* Passwords are hashed with Better Auth's own hasher and stored in the
* `account` table — never in plaintext. If the user already exists they are
* promoted to admin and their password is reset.
*/
import "dotenv/config";
import { prisma } from "@/lib/db";
import { auth } from "@/lib/auth/auth";
async function main() {
const [email, password, ...nameParts] = process.argv.slice(2);
if (!email || !password) {
console.error("Usage: npx tsx scripts/create-admin.ts <email> <password> [name]");
process.exit(1);
}
const name = nameParts.join(" ") || email.split("@")[0];
const ctx = await auth.$context;
const passwordHash = await ctx.password.hash(password);
const existing = await prisma.user.findUnique({ where: { email } });
const user = existing
? await prisma.user.update({
where: { id: existing.id },
data: { role: "admin", emailVerified: true, name: existing.name || name },
})
: await prisma.user.create({
data: { name, email, role: "admin", emailVerified: true },
});
// Upsert the credential account (no compound unique on account, so do it manually).
const cred = await prisma.account.findFirst({
where: { userId: user.id, providerId: "credential" },
select: { id: true },
});
if (cred) {
await prisma.account.update({ where: { id: cred.id }, data: { password: passwordHash } });
} else {
await prisma.account.create({
data: { accountId: user.id, providerId: "credential", userId: user.id, password: passwordHash },
});
}
console.log(`\n✅ Admin ${existing ? "updated" : "created"}: ${email}`);
console.log(` id: ${user.id}`);
console.log(` role: ${user.role}`);
console.log(` login: ${email} / (the password you provided)\n`);
}
main()
.catch((err) => {
console.error("create-admin failed:", err?.message ?? err);
process.exitCode = 1;
})
.finally(() => prisma.$disconnect());