mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 00:22:43 -05:00
feat(admin): make password field optional on create user (#7441)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
committed by
Alex Yang
parent
308f8ae14e
commit
bc9fe98bd0
@@ -173,6 +173,39 @@ describe("Admin plugin", async () => {
|
||||
expect(newUser?.role).toBe("user");
|
||||
});
|
||||
|
||||
it("should allow admin to create users without password", async () => {
|
||||
const res = await client.admin.createUser(
|
||||
{
|
||||
name: "Passwordless User",
|
||||
email: "passwordless@email.com",
|
||||
role: "user",
|
||||
},
|
||||
{
|
||||
headers: adminHeaders,
|
||||
},
|
||||
);
|
||||
expect(res.data?.user?.email).toBe("passwordless@email.com");
|
||||
expect(res.data?.user?.name).toBe("Passwordless User");
|
||||
expect(res.data?.user?.role).toBe("user");
|
||||
|
||||
// User should not be able to sign in with password since no credential account exists
|
||||
const signInRes = await client.signIn.email({
|
||||
email: "passwordless@email.com",
|
||||
password: "anypassword",
|
||||
});
|
||||
expect(signInRes.error).toBeDefined();
|
||||
|
||||
// Clean up
|
||||
await client.admin.removeUser(
|
||||
{
|
||||
userId: res.data?.user?.id || "",
|
||||
},
|
||||
{
|
||||
headers: adminHeaders,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("should allow admin to create user with multiple roles", async () => {
|
||||
const res = await client.admin.createUser(
|
||||
{
|
||||
|
||||
@@ -236,8 +236,9 @@ const createUserBodySchema = z.object({
|
||||
email: z.string().meta({
|
||||
description: "The email of the user",
|
||||
}),
|
||||
password: z.string().meta({
|
||||
description: "The password of the user",
|
||||
password: z.string().optional().meta({
|
||||
description:
|
||||
"The password of the user. If not provided, the user will be created without a credential account (useful for magic link or social login only users).",
|
||||
}),
|
||||
name: z.string().meta({
|
||||
description: "The name of the user",
|
||||
@@ -313,7 +314,7 @@ export const createUser = <O extends AdminOptions>(opts: O) =>
|
||||
$Infer: {
|
||||
body: {} as {
|
||||
email: string;
|
||||
password: string;
|
||||
password?: string | undefined;
|
||||
name: string;
|
||||
role?:
|
||||
| (InferAdminRolesFromOption<O> | InferAdminRolesFromOption<O>[])
|
||||
@@ -374,13 +375,18 @@ export const createUser = <O extends AdminOptions>(opts: O) =>
|
||||
message: ADMIN_ERROR_CODES.FAILED_TO_CREATE_USER,
|
||||
});
|
||||
}
|
||||
const hashedPassword = await ctx.context.password.hash(ctx.body.password);
|
||||
await ctx.context.internalAdapter.linkAccount({
|
||||
accountId: user.id,
|
||||
providerId: "credential",
|
||||
password: hashedPassword,
|
||||
userId: user.id,
|
||||
});
|
||||
// Only create credential account if password is provided
|
||||
if (ctx.body.password) {
|
||||
const hashedPassword = await ctx.context.password.hash(
|
||||
ctx.body.password,
|
||||
);
|
||||
await ctx.context.internalAdapter.linkAccount({
|
||||
accountId: user.id,
|
||||
providerId: "credential",
|
||||
password: hashedPassword,
|
||||
userId: user.id,
|
||||
});
|
||||
}
|
||||
return ctx.json({
|
||||
user: parseUserOutput(ctx.context.options, user) as UserWithRole,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user