docs/content/docs/plugins/username.mdx
The username plugin is a lightweight plugin that adds username support to the email and password authenticator. This allows users to sign in with their username instead of their email.
```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins" // [!code highlight]
export const auth = betterAuth({
emailAndPassword: { // [!code highlight]
enabled: true, // [!code highlight]
}, // [!code highlight]
plugins: [ // [!code highlight]
username() // [!code highlight]
] // [!code highlight]
})
```
Run the migration or generate the schema to add the necessary fields and tables to the database.
<Tabs items={["migrate", "generate"]}>
<Tab value="migrate">
```package-install
npx auth migrate
```
</Tab>
<Tab value="generate">
```package-install
npx auth generate
```
</Tab>
</Tabs>
See the [Schema](#schema) section to add the fields manually.
```ts title="auth-client.ts"
import { createAuthClient } from "better-auth/client"
import { usernameClient } from "better-auth/client/plugins" // [!code highlight]
export const authClient = createAuthClient({
plugins: [ // [!code highlight]
usernameClient() // [!code highlight]
] // [!code highlight]
})
```
To sign up a user with username, you can use the existing signUp.email function provided by the client.
The signUp function should take a new username property in the object.
To sign in a user with username, you can use the signIn.username function provided by the client.
To update the username of a user, you can use the updateUser function provided by the client.
To check if a username is available, you can use the isUsernameAvailable function provided by the client.
if (response?.available) { console.log("Username is available"); } else { console.log("Username is not available"); }
</APIMethod>
## Options
### Min Username Length
The minimum length of the username. Default is `3`.
```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
minUsernameLength: 5
})
]
})
The maximum length of the username. Default is 30.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
maxUsernameLength: 100
})
]
})
A function that validates the username. The function should return false if the username is invalid. By default, the username should only contain alphanumeric characters, underscores, and dots.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
usernameValidator: (username) => {
if (username === "admin") {
return false
}
return true
}
})
]
})
A function that validates the display username. The function should return false if the display username is invalid. By default, no validation is applied to display username.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
displayUsernameValidator: (displayUsername) => {
// Allow only alphanumeric characters, underscores, and hyphens
return /^[a-zA-Z0-9_-]+$/.test(displayUsername)
}
})
]
})
A function that normalizes the username, or false if you want to disable normalization.
By default, usernames are normalized to lowercase, so "TestUser" and "testuser", for example, are considered the same username. The username field will contain the normalized (lower case) username, while displayUsername will contain the original username.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
usernameNormalization: (username) => {
return username.toLowerCase()
.replaceAll("0", "o")
.replaceAll("3", "e")
.replaceAll("4", "a");
}
})
]
})
A function that normalizes the display username, or false to disable normalization.
By default, display usernames are not normalized. When only username is provided during signup or update, the displayUsername will be set to match the original username value (before normalization). You can also explicitly set a displayUsername which will be preserved as-is. For custom normalization, provide a function that takes the display username as input and returns the normalized version.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
displayUsernameNormalization: (displayUsername) => displayUsername.toLowerCase(),
})
]
})
By default, username and display username are validated before normalization. You can change this behavior by setting validationOrder to post-normalization.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
plugins: [
username({
validationOrder: {
username: "post-normalization",
displayUsername: "post-normalization",
}
})
]
})
By default, the plugin exposes an endpoint /is-username-available to check if a username is available. You can disable this endpoint by providing disabledPaths option to the better-auth configuration. This is useful if you want to protect usernames from being enumerated.
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"
const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
disabledPaths: ["/is-username-available"],
plugins: [
username()
]
})
The plugin requires 2 fields to be added to the user table:
export const usernameUserTableFields = [ { name: "username", type: "string", description: "The username of the user", isUnique: true, isOptional: true, }, { name: "displayUsername", type: "string", description: "Non normalized username of the user", isOptional: true, }, ];
<DatabaseTable name="user" fields={usernameUserTableFields} />