Phone Number
Add phone verification-code and password sign-in, recovery, and verified phone management.
The HeroUI phone-number plugin contributes a phone sign-in route, password recovery views, and a verified phone-number card for account settings. Its country selector formats national input as the user types, validates it, and sends an E.164 number to Better Auth.
Setup
Configure Better Auth and your SMS provider
import { betterAuth } from "better-auth"
import { phoneNumber } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
phoneNumber({
otpLength: 6,
requireVerification: true,
sendOTP: ({ phoneNumber, code }) => {
void sms.send({ to: phoneNumber, body: `Your code is ${code}` })
},
sendPasswordResetOTP: ({ phoneNumber, code }) => {
void sms.send({ to: phoneNumber, body: `Your reset code is ${code}` })
}
})
]
})Keep server-side validation as a trust boundary even though the UI normalizes numbers to E.164. Do not log codes in production. Better Auth recommends dispatching the SMS without waiting for the provider response.
Update the schema
Use your normal Better Auth schema generation or migration flow. The user model needs nullable phoneNumber and phoneNumberVerified fields, with phoneNumber kept unique.
Add the client plugin
import { createAuthClient } from "better-auth/react"
import { phoneNumberClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [phoneNumberClient()]
})Register the HeroUI plugin
import { AuthProvider } from "@better-auth-ui/heroui"
import { phoneNumberPlugin } from "@better-auth-ui/heroui/plugins"
<AuthProvider
authClient={authClient}
navigate={navigate}
plugins={[
phoneNumberPlugin({
signIn: true,
passwordSignIn: true,
passwordReset: true,
changePhoneNumber: true
})
]}
>
{children}
</AuthProvider>Allow the new route segments
import { viewPaths } from "@better-auth-ui/core"
import { phoneNumberPlugin } from "@better-auth-ui/heroui/plugins"
const validAuthPaths = new Set([
...Object.values(viewPaths.auth),
...Object.values(phoneNumberPlugin().viewPaths.auth)
])Flow options
| UI option | Default | Server requirement |
|---|---|---|
signIn | true | sendOTP |
passwordSignIn | false | A password credential |
passwordReset | false | sendPasswordResetOTP |
changePhoneNumber | true | sendOTP |
otpLength | 6 | Must match Better Auth otpLength |
Use defaultCountry, countries, and locale to control the selector. Supply an adapter when your application needs different formatting or validation rules.
When password sign-in reports PHONE_NUMBER_NOT_VERIFIED, the UI switches to the code step. Better Auth sends that verification code automatically.
Passwordless phone verification is not a second factor. Better Auth applies 2FA to phone number and password sign-in, but not to passwordless verification.
Enable Better Auth signUpOnVerification to create an account after it verifies an unknown number. If verification requires more user fields, use a custom view.
Options and localization
Prop
Type
Prop
Type
The implementation uses the React phone-number mutations. See the Better Auth phone-number plugin for all server options.
Last updated on