feat(username): Check username availability (#3025)

* feat(username): Check username availability

closes https://github.com/better-auth/better-auth/issues/1553

* add: docs
This commit is contained in:
Maxwell
2025-06-16 17:24:57 +10:00
committed by GitHub
parent 93d5bbe04d
commit be3face70c
3 changed files with 67 additions and 0 deletions

View File

@@ -96,6 +96,23 @@ const data = await authClient.updateUser({
})
```
### Check if username is available
To check if a username is available, you can use the `isUsernameAvailable` function provided by the client.
```ts title="auth-client.ts"
const response = await authClient.isUsernameAvailable({
username: "new-username"
});
if(response.data?.available) {
console.log("Username is available");
} else {
console.log("Username is not available");
}
```
## Schema
The plugin requires 1 field to be added to the user table:

View File

@@ -224,6 +224,42 @@ export const username = (options?: UsernameOptions) => {
});
},
),
isUsernameAvailable: createAuthEndpoint(
"/is-username-available",
{
method: "POST",
body: z.object({
username: z.string({
description: "The username to check",
}),
}),
},
async (ctx) => {
const username = ctx.body.username;
if (!username) {
throw new APIError("UNPROCESSABLE_ENTITY", {
message: ERROR_CODES.INVALID_USERNAME,
});
}
const user = await ctx.context.adapter.findOne<User>({
model: "user",
where: [
{
field: "username",
value: username.toLowerCase(),
},
],
});
if (user) {
return ctx.json({
available: false,
});
}
return ctx.json({
available: true,
});
},
),
},
schema: mergeSchema(schema, options?.schema),
hooks: {

View File

@@ -111,4 +111,18 @@ describe("username", async (it) => {
});
expect(res.error?.status).toBe(422);
});
it("should check if username is unavailable", async () => {
const res = await client.isUsernameAvailable({
username: "new_username_2.1",
});
expect(res.data?.available).toEqual(false);
});
it("should check if username is available", async () => {
const res = await client.isUsernameAvailable({
username: "new_username_2.2",
});
expect(res.data?.available).toEqual(true);
});
});