User & Accounts

除了对用户进行身份验证之外,Better Auth 还提供了一组用于管理用户的方法。这包括更新用户信息、更改密码等。

用户表存储用户身份验证数据 点击此处查看架构

用户表可以使用 附加字段 或插件进行扩展,以存储额外数据。

更新用户

更新用户信息

要更新用户信息,您可以使用客户端提供的 updateUser 函数。updateUser 函数接收一个具有以下属性的对象:

await authClient.updateUser({
    image: "https://example.com/image.jpg",
    name: "John Doe",
})

更改电子邮件

要允许用户更改他们的电子邮件,首先启用 changeEmail 功能,该功能默认禁用。将 changeEmail.enabled 设置为 true

export const auth = betterAuth({
    user: {
        changeEmail: {
            enabled: true,
        }
    }
})

对于具有已验证电子邮件的用户,提供 sendChangeEmailVerification 函数。此函数在用户更改电子邮件时触发,发送包含 URL 和令牌的验证电子邮件。如果当前电子邮件未验证,则更改立即生效,而无需验证。

export const auth = betterAuth({
    user: {
        changeEmail: {
            enabled: true,
            sendChangeEmailVerification: async ({ user, newEmail, url, token }, request) => {
                await sendEmail({
                    to: user.email, // 验证电子邮件必须发送到当前用户电子邮件以批准更改
                    subject: '批准电子邮件更改',
                    text: `点击链接批准更改:${url}`
                })
            }
        }
    }
})

启用后,在客户端使用 changeEmail 函数更新用户的电子邮件。用户在更改之前必须验证他们的当前电子邮件。

await authClient.changeEmail({
    newEmail: "new-email@email.com",
    callbackURL: "/dashboard", //验证后重定向
});

验证后,新电子邮件将在用户表中更新,并向新地址发送确认。

如果当前电子邮件未验证,则新电子邮件会立即更新,而无需验证步骤。

更改密码

用户的密码不存储在用户表中。相反,它存储在账户表中。要更改用户的密码,您可以使用以下方法之一:

POST
/change-password
const { data, error } = await authClient.changePassword({    newPassword: "newpassword1234", // required    currentPassword: "oldpassword1234", // required    revokeOtherSessions: true,});
PropDescriptionType
newPassword
要设置的新密码
string
currentPassword
当前用户密码
string
revokeOtherSessions?
设置为 true 时,将使该用户的所有其他活动会话失效
boolean

设置密码

如果用户使用 OAuth 或其他提供商注册,他们将没有密码或凭证账户。在这种情况下,您可以使用 setPassword 操作为用户设置密码。由于安全原因,此函数只能从服务器调用。我们建议用户通过“忘记密码”流程为他们的账户设置密码。

await auth.api.setPassword({
    body: { newPassword: "password" },
    headers: // 包含用户会话令牌的头部
});

删除用户

Better Auth 提供了一个实用工具,可以从您的数据库中硬删除用户。它默认禁用,但您可以通过传递 enabled:true 轻松启用它

export const auth = betterAuth({
    //...其他配置
    user: {
        deleteUser: { 
            enabled: true
        } 
    }
})

启用后,您可以调用 authClient.deleteUser 以从您的数据库中永久删除用户数据。

在删除前添加验证

为了增加安全性,您可能希望在删除账户之前确认用户的意图。一种常见方法是发送验证电子邮件。Better Auth 提供了 sendDeleteAccountVerification 实用工具用于此目的。 如果您设置了 OAuth 并希望他们能够删除账户而无需再次登录以获取新会话,这尤其必要。

以下是设置方法:

export const auth = betterAuth({
    user: {
        deleteUser: {
            enabled: true,
            sendDeleteAccountVerification: async (
                {
                    user,   // 用户对象
                    url, // 用于删除的自动生成的 URL
                    token  // 验证令牌(可用于生成自定义 URL)
                },
                request  // 原始请求对象(可选)
            ) => {
                // 您的电子邮件发送逻辑在这里
                // 示例:sendEmail(data.user.email, "验证删除", data.url);
            },
        },
    },
});

回调验证的工作原理:

  • 回调 URLsendDeleteAccountVerification 中提供的 URL 是一个预生成的链接,访问时将删除用户数据。
delete-user.ts
await authClient.deleteUser({
    callbackURL: "/goodbye" // 您可以提供删除后的回调 URL 以进行重定向
});
  • 身份验证检查:用户必须登录到他们尝试删除的账户。 如果他们未登录,删除过程将失败。

如果您已发送自定义 URL,您可以使用带有令牌的 deleteUser 方法删除用户。

delete-user.ts
await authClient.deleteUser({
    token
});

身份验证要求

要删除用户,用户必须满足以下要求之一:

  1. 有效密码

如果用户有密码,他们可以通过提供密码来删除其账户。

delete-user.ts
await authClient.deleteUser({
    password: "password"
});
  1. 新鲜会话

用户必须具有 fresh 会话令牌,这意味着用户必须最近登录。如果未提供密码,将检查此项。

默认 session.freshAge 设置为 60 * 60 * 24(1 天)。您可以通过将 session 对象传递给 auth 配置来更改此值。如果设置为 0,则禁用新鲜度检查。如果您未使用电子邮件验证来删除账户,建议不要禁用此检查。

delete-user.ts
await authClient.deleteUser();
  1. 启用电子邮件验证(OAuth 用户需要)

由于 OAuth 用户没有密码,我们需要发送验证电子邮件来确认用户删除账户的意图。如果您已添加 sendDeleteAccountVerification 回调,您可以仅调用 deleteUser 方法,而无需提供任何其他信息。

delete-user.ts
await authClient.deleteUser();
  1. 如果您有一个自定义删除账户页面,并通过 sendDeleteAccountVerification 回调发送该 URL。 然后您需要使用令牌调用 deleteUser 方法来完成删除。
delete-user.ts
await authClient.deleteUser({
    token
});

回调

beforeDelete:此回调在用户被删除之前调用。您可以使用此回调在删除用户之前执行任何清理或额外检查。

auth.ts
export const auth = betterAuth({
    user: {
        deleteUser: {
            enabled: true,
            beforeDelete: async (user) => {
                // 在此处执行任何清理或额外检查
            },
        },
    },
});

您也可以抛出 APIError 来中断删除过程。

auth.ts
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: "管理员账户无法删除",
                    });
                }
            },
        },
    },
});

afterDelete:此回调在用户被删除之后调用。您可以使用此回调在用户被删除之后执行任何清理或额外操作。

auth.ts
export const auth = betterAuth({
    user: {
        deleteUser: {
            enabled: true,
            afterDelete: async (user, request) => {
                // 在此处执行任何清理或额外操作
            },
        },
    },
});

账户

Better Auth 支持多种身份验证方法。每种身份验证方法称为一个提供商。例如,电子邮件和密码身份验证是一个提供商,Google 身份验证是一个提供商,等等。

当用户使用提供商登录时,会为用户创建一个账户。该账户存储提供商返回的身份验证数据。此数据包括访问令牌、刷新令牌以及提供商返回的其他信息。

账户表存储用户的身份验证数据 点击此处查看架构

列出用户账户

要列出用户账户,您可以使用 client.user.listAccounts 方法。它将返回与用户关联的所有账户。

const accounts = await authClient.listAccounts();

令牌加密

Better Auth 默认不加密令牌,这是故意的。我们希望您完全控制加密和解密的方式,而不是内置可能令人困惑或限制的行为。如果您需要存储加密令牌(如 accessToken 或 refreshToken),您可以使用 databaseHooks 在保存到数据库之前加密它们。

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
                    }
                },
            }
        }
    }
})

然后每当您检索账户时,确保在使用它们之前解密令牌。

账户链接

账户链接使用户能够将多个身份验证方法与单个账户关联。在 Better Auth 中,如果提供商确认用户的电子邮件已验证,用户可以将额外的社交登录或 OAuth 提供商连接到其现有账户。

如果禁用账户链接,则无论提供商或电子邮件验证状态如何,都无法链接账户。

auth.ts
export const auth = betterAuth({
    account: {
        accountLinking: {
            enabled: true, 
        }
    },
});

强制链接

您可以指定一个“可信提供商”列表。当用户使用可信提供商登录时,即使提供商未确认电子邮件验证状态,其账户也会自动链接。请谨慎使用,因为这可能会增加账户接管的风险。

auth.ts
export const auth = betterAuth({
    account: {
        accountLinking: {
            enabled: true,
            trustedProviders: ["google", "github"]
        }
    },
});

手动链接账户

已登录的用户可以手动将他们的账户链接到额外的社交提供商或基于凭证的账户。

  • 链接社交账户: 在客户端使用 linkSocial 方法将社交提供商链接到用户账户。

    await authClient.linkSocial({
        provider: "google", // 要链接的提供商
        callbackURL: "/callback" // 链接完成后回调 URL
    });

    您也可以在链接社交账户时请求特定作用域,这些作用域可以与初始身份验证期间使用的作用域不同:

    await authClient.linkSocial({
        provider: "google",
        callbackURL: "/callback",
        scopes: ["https://www.googleapis.com/auth/drive.readonly"] // 请求额外作用域
    });

    您也可以直接使用 ID 令牌链接账户,而无需重定向到提供商的 OAuth 流程:

    await authClient.linkSocial({
        provider: "google",
        idToken: {
            token: "id_token_from_provider",
            nonce: "nonce_used_for_token", // 可选
            accessToken: "access_token", // 可选,某些提供商可能需要
            refreshToken: "refresh_token" // 可选
        }
    });

    这在您已有来自提供商的有效令牌时很有用,例如:

    • 使用原生 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({
        headers: /* 包含用户会话令牌的头部 */,
        password: /* 新密码 */
    });

由于安全原因,setPassword 无法从客户端调用。

账户取消链接

您可以通过提供 providerId 来取消链接用户账户。

await authClient.unlinkAccount({
    providerId: "google"
});

// 取消链接特定账户
await authClient.unlinkAccount({
    providerId: "google",
    accountId: "123"
});

如果账户不存在,它将抛出错误。此外,如果用户只有一个账户,则将阻止取消链接以防止账户锁定(除非将 allowUnlinkingAll 设置为 true)。

auth.ts
export const auth = betterAuth({
    account: {
        accountLinking: {
            allowUnlinkingAll: true
        }
    },
});

On this page