Phone Number
Add phone verification-code and password sign-in to Solid and Zaidan applications.
The Solid/Zaidan registry item adds phone verification-code and password sign-in, phone password recovery, and verified phone-number management. 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
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.
Update the schema and client
Generate or migrate the Better Auth schema so the user model has nullable phoneNumber and phoneNumberVerified fields. Keep phoneNumber unique.
import { createAuthClient } from "@better-auth-ui/solid"
import { phoneNumberClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [phoneNumberClient()]
})Add the registry item
bunx --bun shadcn@latest add https://better-auth-ui.com/r/solid/phone-number.jsonRegister the UI plugin
import { phoneNumberPlugin } from "@/lib/auth/phone-number-plugin"
<AuthProvider
authClient={authClient}
navigate={navigate}
plugins={[
phoneNumberPlugin({
signIn: true,
passwordSignIn: true,
passwordReset: true,
changePhoneNumber: true
})
]}
>
{props.children}
</AuthProvider>Allow the plugin route segments
import { viewPaths } from "@better-auth-ui/core"
import { phoneNumberPlugin } from "@/lib/auth/phone-number-plugin"
const validAuthPathSegments = 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.
Passwordless phone verification bypasses Better Auth 2FA. Phone number and password sign-in still follows the configured second-factor flow.
Set Better Auth signUpOnVerification to create an account after it verifies an unknown number. If verification requires more user fields, build a custom view.
Options and localization
Prop
Type
Prop
Type
The copied components use useSendPhoneNumberOtp and the other Solid phone-number mutation hooks. See the Better Auth phone-number plugin for server behavior and advanced options.
Last updated on