用户与账户
除了对用户进行身份验证之外,Better Auth 还提供了一套管理用户的方法,包括更新用户信息、更改密码等。
【Beyond authenticating users, Better Auth also provides a set of methods to manage users. This includes, updating user information, changing passwords, and more.】
用户表存储了用户的身份验证数据 点击这里查看架构。
【The user table stores the authentication data of the user Click here to view the schema.】
用户表可以通过附加字段或插件进行扩展,以存储额外的数据。
【The user table can be extended using additional fields or by plugins to store additional data.】
更新用户
【Update User】
更新用户信息
【Update User Information】
要更新用户信息,你可以使用客户端提供的 updateUser 函数。updateUser 函数接收一个包含以下属性的对象:
【To update user information, you can use the updateUser function provided by the client. The updateUser function takes an object with the following properties:】
await authClient.updateUser({
image: "https://example.com/image.jpg",
name: "John Doe",
})更改电子邮件
【Change Email】
要允许用户更改其电子邮件,首先需要启用默认关闭的 changeEmail 功能。将 changeEmail.enabled 设置为 true:
【To allow users to change their email, first enable the changeEmail feature, which is disabled by default. Set changeEmail.enabled to true:】
export const auth = betterAuth({
user: {
changeEmail: {
enabled: true,
}
},
emailVerification: {
// Required to send the verification email
sendVerificationEmail: async ({ user, url, token }) => {
void sendEmail({
to: user.email,
})
}
}
})避免等待邮件发送以防止时间攻击。在无服务器平台上,使用 waitUntil 或类似方法来确保邮件已发送。
默认情况下,当用户请求更改他们的电子邮件时,会向新的电子邮件地址发送验证邮件。只有在用户验证了新电子邮件后,电子邮件地址才会更新。
【By default, when a user requests to change their email, a verification email is sent to the new email address. The email is only updated after the user verifies the new email.】
使用当前邮箱确认
【Confirming with Current Email】
为了增加安全性,你可以要求用户在向新邮箱发送验证邮件之前,通过他们的当前邮箱确认更改。要做到这一点,请提供 sendChangeEmailConfirmation 函数。
【For added security, you can require users to confirm the change via their current email before
the verification email is sent to the new address. To do this, provide the sendChangeEmailConfirmation function.】
export const auth = betterAuth({
user: {
changeEmail: {
enabled: true,
sendChangeEmailConfirmation: async ({ user, newEmail, url, token }, request) => {
void sendEmail({
to: user.email, // Sent to the CURRENT email
subject: 'Approve email change',
text: `Click the link to approve the change to ${newEmail}: ${url}`
})
}
}
},
// ...
})在未验证的情况下更新
【Updating Without Verification】
如果你希望允许用户在其当前邮箱未验证的情况下立即更新邮箱,可以启用 updateEmailWithoutVerification。
【If you want to allow users to update their email immediately without verification (only if their current email is NOT verified), you can enable updateEmailWithoutVerification.】
export const auth = betterAuth({
user: {
changeEmail: {
enabled: true,
updateEmailWithoutVerification: true
}
}
})如果 updateEmailWithoutVerification 为 false(默认值),即使当前邮箱未验证,邮箱也不会更新,直到新邮箱被验证。
客户端使用
【Client Usage】
在客户端使用 changeEmail 函数来启动该过程。
【Use the changeEmail function on the client to initiate the process.】
await authClient.changeEmail({
newEmail: "new-email@email.com",
callbackURL: "/dashboard", // to redirect after verification
});更改密码
【Change 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 |
设置密码
【Set Password】
如果用户是通过 OAuth 或其他提供商注册的,他们将没有密码或凭证账号。在这种情况下,你可以使用 setPassword 操作为用户设置密码。出于安全原因,此功能只能从服务器端调用。我们建议让用户通过“忘记密码”流程为他们的账户设置密码。
【If a user was registered using OAuth or other providers, they won't have a password or a credential account. In this case, you can use the setPassword action to set a password for the user. For security reasons, this function can only be called from the server. We recommend having users go through a 'forgot password' flow to set a password for their account.】
await auth.api.setPassword({
body: {
newPassword: "new-password",
},
headers: await headers() // headers containing the user's session token
});验证密码
【Verify Password】
verifyPassword 函数允许你验证用户当前的密码。这对于在执行诸如更新安全设置等敏感操作之前确认用户身份非常有用。此函数只能从服务器端调用。
【The verifyPassword function allows you to verify a user's current password. This is useful for confirming user identity before performing sensitive operations like updating security settings. This function can only be called from the server.】
await auth.api.verifyPassword({
body: {
password: "user-password" // required
},
headers: await headers() // headers containing the user's session token
});For OAuth users who don't have passwords, consider using email verification or fresh session checks for sensitive operations instead.
删除用户
【Delete User】
Better Auth 提供了一个实用工具,可以从你的数据库中彻底删除用户。它默认是禁用的,但你可以通过传递 enabled:true 轻松启用它。
【Better Auth provides a utility to hard delete a user from your database. It's disabled by default, but you can enable it easily by passing enabled:true】
export const auth = betterAuth({
//...other config
user: {
deleteUser: {
enabled: true
}
}
})启用后,你可以调用 authClient.deleteUser 从数据库中永久删除用户数据。
【Once enabled, you can call authClient.deleteUser to permanently delete user data from your database.】
删除前添加验证
【Adding Verification Before Deletion】
为了增强安全性,你可能希望在删除用户账户之前确认用户的意图。一种常见的方法是发送验证电子邮件。Better Auth 提供了一个 sendDeleteAccountVerification 工具来实现这一目的。 如果你已经设置了 OAuth,并且希望用户能够删除账户而不必再次登录以获取新的会话,这一点尤其必要。
【For added security, you’ll likely want to confirm the user’s intent before deleting their account. A common approach is to send a verification email. Better Auth provides a sendDeleteAccountVerification utility for this purpose.
This is especially needed if you have OAuth setup and want them to be able to delete their account without forcing them to login again for a fresh session.】
以下是你可以设置的方法:
【Here’s how you can set it up:】
export const auth = betterAuth({
user: {
deleteUser: {
enabled: true,
sendDeleteAccountVerification: async (
{
user, // The user object
url, // The auto-generated URL for deletion
token // The verification token (can be used to generate custom URL)
},
request // The original request object (optional)
) => {
// Your email sending logic here
// Example: sendEmail(data.user.email, "Verify Deletion", data.url);
},
},
},
});回调验证的工作原理:
- 回调 URL:在
sendDeleteAccountVerification中提供的 URL 是一个预先生成的链接,访问该链接时会删除用户数据。
await authClient.deleteUser({
callbackURL: "/goodbye" // you can provide a callback URL to redirect after deletion
});- 身份验证检查:用户必须登录他们尝试删除的账户。如果未登录,删除过程将失败。
如果你已经发送了自定义 URL,你可以使用带有令牌的 deleteUser 方法来删除用户。
【If you have sent a custom URL, you can use the deleteUser method with the token to delete the user.】
await authClient.deleteUser({
token
});身份验证要求
【Authentication Requirements】
要删除用户,该用户必须满足以下条件之一:
【To delete a user, the user must meet one of the following requirements:】
- 有效的密码
如果用户有密码,他们可以通过提供密码来删除自己的账户。
【if the user has a password, they can delete their account by providing the password.】
await authClient.deleteUser({
password: "password"
});- 新会话
用户必须拥有一个“新鲜”的会话令牌,这意味着用户必须最近登录过。如果未提供密码,将检查这一点。
【The user must have a fresh session token, meaning the user must have signed in recently. This is checked if the password is not provided.】
默认情况下,session.freshAge 设置为 60 * 60 * 24(1 天)。你可以通过将 session 对象传递给 auth 配置来更改此值。如果设置为 0,则新鲜度检查将被禁用。如果你在删除账户时没有使用电子邮件验证,建议不要禁用此检查。
await authClient.deleteUser();- 已启用电子邮件验证(OAuth 用户需要)
由于 OAuth 用户没有密码,我们需要发送验证电子邮件以确认用户删除其账户的意图。如果你已经添加了 sendDeleteAccountVerification 回调,则只需调用 deleteUser 方法而无需提供其他信息。
【As OAuth users don't have a password, we need to send a verification email to confirm the user's intent to delete their account. If you have already added the sendDeleteAccountVerification callback, you can just call the deleteUser method without providing any other information.】
await authClient.deleteUser();- 如果你有自定义的删除账户页面,并通过
sendDeleteAccountVerification回调发送了该 URL,那么你需要使用该令牌调用deleteUser方法以完成删除。
await authClient.deleteUser({
token
});回调
【Callbacks】
beforeDelete:此回调在用户被删除之前调用。你可以使用此回调在删除用户之前执行任何清理工作或额外的检查。
export const auth = betterAuth({
user: {
deleteUser: {
enabled: true,
beforeDelete: async (user) => {
// Perform any cleanup or additional checks here
},
},
},
});you can also throw APIError to interrupt the deletion process.
import { betterAuth } from "better-auth";
import { APIError } from "better-auth/api";
export const auth = betterAuth({
user: {
deleteUser: {
enabled: true,
beforeDelete: async (user, request) => {
if (user.email.includes("admin")) {
throw new APIError("BAD_REQUEST", {
message: "Admin accounts can't be deleted",
});
}
},
},
},
});afterDelete:此回调在用户被删除后调用。你可以使用此回调在用户被删除后执行任何清理或其他操作。
export const auth = betterAuth({
user: {
deleteUser: {
enabled: true,
afterDelete: async (user, request) => {
// Perform any cleanup or additional actions here
},
},
},
});账户
【Accounts】
Better Auth 支持多种认证方式。每种认证方式称为一个提供者。例如,邮箱和密码认证是一种提供者,谷歌认证是一种提供者,等等。
【Better Auth supports multiple authentication methods. Each authentication method is called a provider. For example, email and password authentication is a provider, Google authentication is a provider, etc.】
当用户使用提供商登录时,会为该用户创建一个账户。该账户存储提供商返回的身份验证数据。这些数据包括访问令牌、刷新令牌以及提供商返回的其他信息。
【When a user signs in using a provider, an account is created for the user. The account stores the authentication data returned by the provider. This data includes the access token, refresh token, and other information returned by the provider.】
账户表存储用户的身份验证数据 点击此处查看架构
【The account table stores the authentication data of the user Click here to view the schema】
列出用户账户
【List User Accounts】
要列出用户账户,你可以使用 client.user.listAccounts 方法。该方法将返回与用户关联的所有账户。
【To list user accounts you can use client.user.listAccounts method. Which will return all accounts associated with a user.】
const accounts = await authClient.listAccounts();令牌加密
【Token Encryption】
Better Auth 默认不会加密令牌,这是有意为之的。我们希望你能够完全控制加密和解密的处理方式,而不是内置可能令人困惑或有限制的行为。如果你需要存储加密的令牌(例如 accessToken 或 refreshToken),可以使用 databaseHooks 在将它们保存到数据库之前进行加密。
【Better Auth doesn’t encrypt tokens by default and that’s intentional. We want you to have full control over how encryption and decryption are handled, rather than baking in behavior that could be confusing or limiting. If you need to store encrypted tokens (like accessToken or refreshToken), you can use databaseHooks to encrypt them before they’re saved to your database.】
export const auth = betterAuth({
databaseHooks: {
account: {
create: {
before(account, context) {
const withEncryptedTokens = { ...account };
if (account.accessToken) {
const encryptedAccessToken = encrypt(account.accessToken)
withEncryptedTokens.accessToken = encryptedAccessToken;
}
if (account.refreshToken) {
const encryptedRefreshToken = encrypt(account.refreshToken);
withEncryptedTokens.refreshToken = encryptedRefreshToken;
}
return {
data: withEncryptedTokens
}
},
}
}
}
})然后,每当你恢复账户时,确保在使用令牌之前先解密它们。
【Then whenever you retrieve back the account make sure to decrypt the tokens before using them.】
帐号关联
【Account Linking】
账户关联使用户能够将多种身份验证方法与一个账户关联。通过 Better Auth,用户可以将额外的社交登录或 OAuth 提供商连接到现有账户,如果提供商确认用户的电子邮件已验证。
【Account linking enables users to associate multiple authentication methods with a single account. With Better Auth, users can connect additional social sign-ons or OAuth providers to their existing accounts if the provider confirms the user's email as verified.】
如果账户关联被禁用,则无法关联任何账户,无论提供商或电子邮件验证状态如何。
【If account linking is disabled, no accounts can be linked, regardless of the provider or email verification status.】
export const auth = betterAuth({
account: {
accountLinking: {
enabled: true,
}
},
});强制链接
【Forced Linking】
你可以指定“受信任的提供商”列表。当用户使用受信任的提供商登录时,即使该提供商未确认电子邮件验证状态,他们的账户也会自动关联。请谨慎使用,因为这可能增加账户被接管的风险。
【You can specify a list of "trusted providers." When a user logs in using a trusted provider, their account will be automatically linked even if the provider doesn’t confirm the email verification status. Use this with caution as it may increase the risk of account takeover.】
export const auth = betterAuth({
account: {
accountLinking: {
enabled: true,
trustedProviders: ["google", "github"]
}
},
});手动关联账户
【Manually Linking Accounts】
已登录的用户可以手动将其账户链接到其他社交平台或基于凭证的账户。
【Users already signed in can manually link their account to additional social providers or credential-based accounts.】
-
关联社交账户: 使用客户端的
linkSocial方法将社交提供者与用户账户关联。await authClient.linkSocial({ provider: "google", // Provider to link callbackURL: "/callback" // Callback URL after linking completes });在关联社交账户时,你也可以请求特定的权限范围,这些范围可以与初始认证时使用的权限不同:
await authClient.linkSocial({ provider: "google", callbackURL: "/callback", scopes: ["https://www.googleapis.com/auth/drive.readonly"] // Request additional scopes });你也可以直接使用 ID 令牌链接账户,无需重定向到提供商的 OAuth 流程:
await authClient.linkSocial({ provider: "google", idToken: { token: "id_token_from_provider", nonce: "nonce_used_for_token", // Optional accessToken: "access_token", // Optional, may be required by some providers refreshToken: "refresh_token" // Optional } });当你已经拥有来自提供者的有效令牌时,这会很有用,例如:
- 使用原生 SDK 登录后
- 使用处理身份验证的移动应用时
- 实现自定义 OAuth 流程时
ID 令牌必须有效,并且提供者必须支持 ID 令牌验证。
如果你希望用户能够使用与账户不同的电子邮件地址关联社交账户,或者如果你希望使用不返回电子邮件地址的提供商,则需要在账户关联设置中启用此功能。
auth.ts export const auth = betterAuth({ account: { accountLinking: { allowDifferentEmails: true } }, });如果你希望新关联的账户更新用户信息,你需要在账户关联设置中启用此功能。
auth.ts export const auth = betterAuth({ account: { accountLinking: { updateUserInfoOnLink: true } }, }); -
关联基于凭证的账户: 要关联基于凭证的账户(例如电子邮件和密码),用户可以启动“忘记密码”流程,或者你可以在服务器上调用
setPassword方法。await auth.api.setPassword({ body: { newPassword: "new-password", // required }, headers: await headers() // headers containing the user's session token });
setPassword 出于安全原因不能从客户端调用。
账号解绑
【Account Unlinking】
你可以通过提供 providerId 来取消关联用户账户。
【You can unlink a user account by providing a providerId.】
await authClient.unlinkAccount({
providerId: "google"
});
// Unlink a specific account
await authClient.unlinkAccount({
providerId: "google",
accountId: "123"
});如果账户不存在,将会抛出错误。此外,如果用户只有一个账户,将会阻止取消关联以防止账户被锁定(除非将 allowUnlinkingAll 设置为 true)。
【If the account doesn't exist, it will throw an error. Additionally, if the user only has one account, unlinking will be prevented to stop account lockout (unless allowUnlinkingAll is set to true).】
export const auth = betterAuth({
account: {
accountLinking: {
allowUnlinkingAll: true
}
},
});