Skills
Skill 3 of 6
Configure email verification, implement password reset flows, set password policies, and customise hashing algorithms for Better Auth email/password authentication.
1 minute · 327 words · 13 sections
Install
npx skills add better-auth/skills --skill email-and-password-best-practicesnpx skills add better-auth/skills/plugin marketplace add better-auth/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
emailAndPassword: { enabled: true }emailVerification.sendVerificationEmailsendResetPassword for password reset flowsnpx auth@latest migrateConfigure emailVerification.sendVerificationEmail to verify user email addresses.
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function
export const auth = betterAuth({
emailVerification: {
sendVerificationEmail: async ({ user, url, token }, request) => {
await sendEmail({
to: user.email,
subject: "Verify your email address",
text: `Click the link to verify your email: ${url}`,
});
},
},
});Note: The url parameter contains the full verification link. The token is available if you need to build a custom verification URL.
For stricter security, enable emailAndPassword.requireEmailVerification to block sign-in until the user verifies their email. When enabled, unverified users will receive a new verification email on each sign-in attempt.
export const auth = betterAuth({
emailAndPassword: {
requireEmailVerification: true,
},
});Note: This requires sendVerificationEmail to be configured and only applies to email/password sign-ins.
Implement client-side validation for immediate user feedback and reduced server load.
Always use absolute URLs (including the origin) for callback URLs in sign-up and sign-in requests. This prevents Better Auth from needing to infer the origin, which can cause issues when your backend and frontend are on different domains.
const { data, error } = await authClient.signUp.email({
callbackURL: "https://example.com/callback", // absolute URL with origin
});Provide sendResetPassword in the email and password config to enable password resets.
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
// Custom email sending function to send reset-password email
sendResetPassword: async ({ user
Built-in protections: background email sending (timing attack prevention), dummy operations on invalid requests, constant response messages regardless of user existence.
On serverless platforms, configure a background task handler:
export const auth = betterAuth({
advanced: {
backgroundTasks: {
handler: (promise) => {
// Use platform-specific methods like waitUntil
waitUntil(promise);
},
},
},
});Tokens expire after 1 hour by default. Configure with resetPasswordTokenExpiresIn (in seconds):
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
resetPasswordTokenExpiresIn: 60 * 30, // 30 minutes
},
});Tokens are single-use — deleted immediately after successful reset.
Enable revokeSessionsOnPasswordReset to invalidate all existing sessions on password reset:
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
revokeSessionsOnPasswordReset: true,
},
});Password length limits (configurable):
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
minPasswordLength: 12,
maxPasswordLength: 256,
},
});Call requestPasswordReset to send the reset link. Triggers the sendResetPassword function from your config.
const data = await auth.api.requestPasswordReset({
body: {
email: "john.doe@example.com", // required
redirectTo: "https://example.com/reset-password",
},
});Or authClient:
const { data, error } = await authClient.requestPasswordReset({
email: "john.doe@example.com", // required
redirectTo: "https://example.com/reset-password",
});Note: While the email is required, we also recommend configuring the redirectTo for a smoother user experience.
Default: scrypt (Node.js native, no external dependencies).
To use Argon2id or another algorithm, provide custom hash and verify functions:
import { betterAuth } from "better-auth";
import { hash, verify, type Options } from "@node-rs/argon2";
const argon2Options: Options = {
memoryCost: 65536, // 64 MiB
timeCost: 3, // 3 iterations
parallelism: 4, // 4 parallel lanes
Note: If you switch hashing algorithms on an existing system, users with passwords hashed using the old algorithm won’t be able to sign in. Plan a migration strategy if needed.
Configure email verification, implement password reset flows, set password policies, and customise hashing algorithms for Better Auth email/password authentication. Use when users need to set up login, sign-in, sign-up, credential authentication, or password security with Better Auth.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 1 September 2026.SKILL.md, not by matching a directory convention. 2 distinct layouts observed: better-auth/*/SKILL.md, */SKILL.md..claude-plugin/marketplace.json by Alex Yang, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./better-auth/skills.md, and each skill at its own .md URL.