电子邮箱和密码
电子邮件和密码认证是许多应用常用的一种方法。Better Auth 提供了内置的电子邮件和密码认证器,你可以轻松地将其集成到你的项目中。
【Email and password authentication is a common method used by many applications. Better Auth provides a built-in email and password authenticator that you can easily integrate into your project.】
如果你更喜欢基于用户名的认证,请查看 用户名插件。它在电子邮件和密码认证的基础上增加了对用户名的支持。
启用电子邮件和密码
【Enable Email and Password】
要启用电子邮件和密码认证,你需要在 auth 配置中将 emailAndPassword.enabled 选项设置为 true。
【To enable email and password authentication, you need to set the emailAndPassword.enabled option to true in the auth configuration.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
},
});如果未启用,你将无法使用电子邮件和密码登录或注册。
用法
【Usage】
注册
【Sign Up】
要注册一个用户,你可以使用客户端提供的 signUp.email 函数。
【To sign a user up, you can use the signUp.email function provided by the client.】
const { data, error } = await authClient.signUp.email({ name: "John Doe", // required email: "john.doe@example.com", // required password: "password1234", // required image: "https://example.com/image.png", callbackURL: "https://example.com/callback",});| Prop | Description | Type |
|---|---|---|
name | The name of the user. | string |
email | The email address of the user. | string |
password | The password of the user. It should be at least 8 characters long and max 128 by default. | string |
image? | An optional profile image of the user. | string |
callbackURL? | An optional URL to redirect to after the user signs up. | string |
这些是注册邮箱端点的默认属性,不过通过额外字段或特殊插件,你也可以向端点传递更多属性。
登录
【Sign In】
要登录用户,你可以使用客户端提供的 signIn.email 函数。
【To sign a user in, you can use the signIn.email function provided by the client. 】
const { data, error } = await authClient.signIn.email({ email: "john.doe@example.com", // required password: "password1234", // required rememberMe: true, callbackURL: "https://example.com/callback",});| Prop | Description | Type |
|---|---|---|
email | The email address of the user. | string |
password | The password of the user. It should be at least 8 characters long and max 128 by default. | string |
rememberMe? | If false, the user will be signed out when the browser is closed. (optional) (default: true) | boolean |
callbackURL? | An optional URL to redirect to after the user signs in. (optional) | string |
这些是登录邮箱端点的默认属性,但通过额外字段或特殊插件,你可以向端点传递不同的属性。
登出
【Sign Out】
要注销用户,你可以使用客户端提供的 signOut 函数。
【To sign a user out, you can use the signOut function provided by the client.】
await authClient.signOut();你可以传递 fetchOptions 来在成功时重定向
【you can pass fetchOptions to redirect onSuccess】
await authClient.signOut({
fetchOptions: {
onSuccess: () => {
router.push("/login"); // redirect to login page
},
},
});邮箱验证
【Email Verification】
要启用电子邮件验证,你需要传递一个函数,该函数会发送包含链接的验证电子邮件。sendVerificationEmail 函数接受一个包含以下属性的数据对象:
【To enable email verification, you need to pass a function that sends a verification email with a link. The sendVerificationEmail function takes a data object with the following properties:】
user:用户对象。url:发送给用户的包含令牌的 URL。token:用于完成电子邮件验证的验证令牌。
并将一个 request 对象作为第二个参数。
【and a request object as the second parameter.】
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function
export const auth = betterAuth({
emailVerification: {
sendVerificationEmail: async ( { user, url, token }, request) => {
void sendEmail({
to: user.email,
subject: "Verify your email address",
text: `Click the link to verify your email: ${url}`,
});
},
},
});避免等待邮件发送以防止时间攻击。在无服务器平台上,使用 waitUntil 或类似方法来确保邮件已发送。
在客户端,你可以使用 sendVerificationEmail 函数向用户发送验证链接。这将触发你在 auth 配置中提供的 sendVerificationEmail 函数。
【On the client side you can use sendVerificationEmail function to send verification link to user. This will trigger the sendVerificationEmail function you provided in the auth configuration.】
一旦用户点击电子邮件中的链接,如果令牌有效,用户将被重定向到 callbackURL 参数中提供的 URL。如果令牌无效,用户将被重定向到 callbackURL 参数中提供的 URL,并在查询字符串中附带错误信息 ?error=invalid_token。
【Once the user clicks on the link in the email, if the token is valid, the user will be redirected to the URL provided in the callbackURL parameter. If the token is invalid, the user will be redirected to the URL provided in the callbackURL parameter with an error message in the query string ?error=invalid_token.】
需要邮箱验证
【Require Email Verification】
如果启用需要邮箱验证,用户必须在登录前验证他们的邮箱。每次用户尝试登录时,都会调用 sendVerificationEmail。
【If you enable require email verification, users must verify their email before they can log in. And every time a user tries to sign in, sendVerificationEmail is called.】
这仅在你实现了 sendVerificationEmail 并且用户尝试使用电子邮件和密码登录时才有效。
export const auth = betterAuth({
emailAndPassword: {
requireEmailVerification: true,
},
});如果用户在未验证其电子邮件的情况下尝试登录,你可以处理错误并向用户显示一条消息。
【If a user tries to sign in without verifying their email, you can handle the error and show a message to the user.】
await authClient.signIn.email(
{
email: "email@example.com",
password: "password",
},
{
onError: (ctx) => {
// Handle the error
if (ctx.error.status === 403) {
alert("Please verify your email address");
}
//you can also show the original error message
alert(ctx.error.message);
},
}
);手动触发电子邮件验证
【Triggering manually Email Verification】
你可以通过调用 sendVerificationEmail 函数手动触发电子邮件验证。
【You can trigger the email verification manually by calling the sendVerificationEmail function.】
await authClient.sendVerificationEmail({
email: "user@email.com",
callbackURL: "/", // The redirect URL after verification
});请求重置密码
【Request Password Reset】
为了允许用户重置密码,首先需要向邮箱和密码验证器提供 sendResetPassword 函数。sendResetPassword 函数接收一个包含以下属性的数据对象:
【To allow users to reset a password first you need to provide sendResetPassword function to the email and password authenticator. The sendResetPassword function takes a data object with the following properties:】
user:用户对象。url:发送给用户的包含令牌的 URL。token:用于完成密码重置的验证令牌。
并将一个 request 对象作为第二个参数。
【and a request object as the second parameter.】
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.`);
},
},
});避免等待邮件发送以防止时间攻击。在无服务器平台上,使用 waitUntil 或类似方法来确保邮件已发送。
此外,你可以提供一个 onPasswordReset 回调,以在密码成功重置后执行逻辑。
【Additionally, you can provide an onPasswordReset callback to execute logic after a password has been successfully reset.】
配置好服务器后,你可以调用 requestPasswordReset 函数向用户发送重置密码的链接。如果用户存在,它将触发你在身份验证配置中提供的 sendResetPassword 函数。
【Once you configured your server you can call requestPasswordReset function to send reset password link to user. If the user exists, it will trigger the sendResetPassword function you provided in the auth config.】
const { data, error } = await authClient.requestPasswordReset({ email: "john.doe@example.com", // required redirectTo: "https://example.com/reset-password",});| Prop | Description | Type |
|---|---|---|
email | The email address of the user to send a password reset email to | string |
redirectTo? | The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter ?error=INVALID_TOKEN. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN | string |
当用户点击电子邮件中的链接时,他们将被重定向到重置密码页面。你可以将重置密码页面添加到你的应用中。然后你可以使用 resetPassword 函数来重置密码。它接受一个包含以下属性的对象:
【When a user clicks on the link in the email, they will be redirected to the reset password page. You can add the reset password page to your app. Then you can use resetPassword function to reset the password. It takes an object with the following properties:】
newPassword:用户的新密码。
const { data, error } = await authClient.resetPassword({
newPassword: "password1234",
token,
});const token = new URLSearchParams(window.location.search).get("token");if (!token) { // Handle the error}const { data, error } = await authClient.resetPassword({ newPassword: "password1234", // required token, // required});| Prop | Description | Type |
|---|---|---|
newPassword | The new password to set | string |
token | The token to reset the password | string |
更新密码
【Update password】
用户的密码不会存储在用户表中,而是存储在账户表中。要更改用户的密码,可以使用以下方法之一:
【A user's password isn't stored in the user table. Instead, it's stored in the account table. To change the password of a user, you can use one of the following approaches:】
const { data, error } = await authClient.changePassword({ newPassword: "newpassword1234", // required currentPassword: "oldpassword1234", // required revokeOtherSessions: true,});| Prop | Description | Type |
|---|---|---|
newPassword | The new password to set | string |
currentPassword | The current user password | string |
revokeOtherSessions? | When set to true, all other active sessions for this user will be invalidated | boolean |
配置
【Configuration】
密码
Better Auth 将密码存储在 account 表中,并将 providerId 设置为 credential。
【Better Auth stores passwords inside the account table with providerId set to credential.】
密码哈希:Better Auth 使用 scrypt 来哈希密码。scrypt 算法设计得既慢又占用大量内存,以增加攻击者暴力破解密码的难度。OWASP 建议如果无法使用 argon2id,可以使用 scrypt。我们选择使用 scrypt,因为它在 Node.js 中原生支持。
你可以通过在 emailAndPassword 配置中设置 password 选项来传递自定义密码哈希算法。
【You can pass custom password hashing algorithm by setting password option in the emailAndPassword configuration.】
示例
下面是一个自定义密码哈希以使用 Argon2 的示例:
【Here's an example of customizing the password hashing to use Argon2:】
import { hash, type Options, verify } from "@node-rs/argon2";
const opts: Options = {
memoryCost: 65536, // 64 MiB
timeCost: 3, // 3 iterations
parallelism: 4, // 4 lanes
outputLen: 32, // 32 bytes
algorithm: 2, // Argon2id
};
export async function hashPassword(password: string) {
const result = await hash(password, opts);
return result;
}
export async function verifyPassword(data: { password: string; hash: string }) {
const { password, hash } = data;
const result = await verify(hash, password, opts);
return result;
}import { betterAuth } from "better-auth";
import { hashPassword, verifyPassword } from "./password";
export const auth = betterAuth({
emailAndPassword: {
//...rest of the options
enabled: true,
password: {
hash: hashPassword,
verify: verifyPassword,
},
},
});Prop
Type