email-and-password-best-practices by better-auth/skills
npx skills add https://github.com/better-auth/skills --skill email-and-password-best-practicesemailAndPassword: { enabled: true }emailVerification.sendVerificationEmailsendResetPasswordnpx @better-auth/cli@latest migrate配置 emailVerification.sendVerificationEmail 以验证用户电子邮件地址。
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}`,
});
},
},
});
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
注意:url 参数包含完整的验证链接。如果您需要构建自定义验证 URL,可以使用 token。
为了更严格的安全性,启用 emailAndPassword.requireEmailVerification 以阻止用户在验证电子邮件前登录。启用后,未验证的用户在每次尝试登录时都会收到新的验证邮件。
export const auth = betterAuth({
emailAndPassword: {
requireEmailVerification: true,
},
});
注意:这需要配置 sendVerificationEmail,并且仅适用于电子邮件/密码登录。
实施客户端验证,以提供即时用户反馈并减少服务器负载。
在注册和登录请求中,始终为回调 URL 使用绝对 URL(包括来源)。这可以防止 Better Auth 需要推断来源,当您的后端和前端位于不同域时,这可能会导致问题。
const { data, error } = await authClient.signUp.email({
callbackURL: "https://example.com/callback", // absolute URL with origin
});
在电子邮件和密码配置中提供 sendResetPassword 以启用密码重置。
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
// 自定义发送重置密码邮件的函数
sendResetPassword: async ({ user, url, token }, request) => {
void sendEmail({
to: user.email,
subject: "Reset your password",
text: `Click the link to reset your password: ${url}`,
});
},
// 可选的事件钩子
onPasswordReset: async ({ user }, request) => {
// your logic here
console.log(`Password for user ${user.email} has been reset.`);
},
},
});
内置保护:后台发送电子邮件(防止时序攻击)、对无效请求执行虚拟操作、无论用户是否存在都返回一致的响应消息。
在无服务器平台上,配置后台任务处理器:
export const auth = betterAuth({
advanced: {
backgroundTasks: {
handler: (promise) => {
// 使用平台特定的方法,如 waitUntil
waitUntil(promise);
},
},
},
});
令牌默认在 1 小时后过期。使用 resetPasswordTokenExpiresIn(以秒为单位)进行配置:
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
resetPasswordTokenExpiresIn: 60 * 30, // 30 minutes
},
});
令牌为一次性使用——在成功重置后立即删除。
启用 revokeSessionsOnPasswordReset 以在密码重置时使所有现有会话失效:
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
revokeSessionsOnPasswordReset: true,
},
});
密码长度限制(可配置):
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
minPasswordLength: 12,
maxPasswordLength: 256,
},
});
调用 requestPasswordReset 来发送重置链接。这会触发您配置中的 sendResetPassword 函数。
const data = await auth.api.requestPasswordReset({
body: {
email: "john.doe@example.com", // required
redirectTo: "https://example.com/reset-password",
},
});
或者使用 authClient:
const { data, error } = await authClient.requestPasswordReset({
email: "john.doe@example.com", // required
redirectTo: "https://example.com/reset-password",
});
注意:虽然 email 是必需的,但我们建议配置 redirectTo 以获得更流畅的用户体验。
默认:scrypt(Node.js 原生,无外部依赖)。
要使用 Argon2id 或其他算法,请提供自定义的 hash 和 verify 函数:
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
outputLen: 32, // 32 byte output
algorithm: 2, // Argon2id variant
};
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
password: {
hash: (password) => hash(password, argon2Options),
verify: ({ password, hash: storedHash }) =>
verify(storedHash, password, argon2Options),
},
},
});
注意:如果您在现有系统上切换哈希算法,使用旧算法哈希密码的用户将无法登录。如果需要,请规划迁移策略。
每周安装量
3.8K
代码仓库
GitHub 星标数
147
首次出现
2026年2月10日
安全审计
安装于
opencode3.6K
codex3.6K
gemini-cli3.6K
github-copilot3.5K
amp3.5K
kimi-cli3.4K
emailAndPassword: { enabled: true }emailVerification.sendVerificationEmailsendResetPassword for password reset flowsnpx @better-auth/cli@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, url, token }, request) => {
void sendEmail({
to: user.email,
subject: "Reset your password",
text: `Click the link to reset your password: ${url}`,
});
},
// Optional event hook
onPasswordReset: async ({ user }, request) => {
// your logic here
console.log(`Password for user ${user.email} has been reset.`);
},
},
});
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
outputLen: 32, // 32 byte output
algorithm: 2, // Argon2id variant
};
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
password: {
hash: (password) => hash(password, argon2Options),
verify: ({ password, hash: storedHash }) =>
verify(storedHash, password, argon2Options),
},
},
});
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.
Weekly Installs
3.8K
Repository
GitHub Stars
147
First Seen
Feb 10, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode3.6K
codex3.6K
gemini-cli3.6K
github-copilot3.5K
amp3.5K
kimi-cli3.4K
97,600 周安装