OAuth

Better Auth 内置支持 OAuth 2.0 和 OpenID Connect。这使您能够通过流行的 OAuth 提供商(如 Google、Facebook、GitHub 等)对用户进行身份验证。

如果您所需的提供商未直接受支持,可以使用 通用 OAuth 插件 进行自定义集成。

配置社交登录提供商

要启用社交登录提供商,您需要提供该提供商的 clientIdclientSecret

以下是如何配置 Google 作为提供商的示例:

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  // 其他配置...
  socialProviders: {
    google: {
      clientId: "YOUR_GOOGLE_CLIENT_ID",
      clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
    },
  },
});

使用方法

登录

要使用社交提供商登录,您可以使用 authClientsignIn.social 函数,或在服务器端使用 auth.api

// 客户端用法
await authClient.signIn.social({
  provider: "google", // 或其他任何提供商 ID
})
// 服务器端用法
await auth.api.signInSocial({
  body: {
    provider: "google", // 或其他任何提供商 ID
  },
});

关联账户

要将账户关联到社交提供商,您可以使用 authClientlinkAccount 函数,或在服务器端使用 auth.api

await authClient.linkSocial({
  provider: "google", // 或其他任何提供商 ID
})

服务器端用法:

await auth.api.linkSocialAccount({
  body: {
    provider: "google", // 或其他任何提供商 ID
  },
  headers: // 传递包含认证令牌的请求头
});

获取访问令牌

要获取社交提供商的访问令牌,您可以使用 authClientgetAccessToken 函数,或在服务器端使用 auth.api。当您使用此端点时,如果访问令牌已过期,它将被自动刷新。

const { accessToken } = await authClient.getAccessToken({
  providerId: "google", // 或其他任意提供商 ID
  accountId: "accountId", // 可选,用于获取特定账户的访问令牌
})

服务器端用法:

await auth.api.getAccessToken({
  body: {
    providerId: "google", // 或其他任意提供商 ID
    accountId: "accountId", // 可选,用于获取特定账户的访问令牌
    userId: "userId", // 可选,如果未在请求头中提供认证令牌
  },
  headers: // 传递包含认证令牌的请求头
});

获取提供商提供的账户信息

要获取提供商特定的账户信息,您可以使用 authClientaccountInfo 函数,或在服务器端使用 auth.api

const info = await authClient.accountInfo({
  accountId: "accountId", // 此处传入提供商提供的账户 ID,系统会根据账户 ID 自动检测提供商
})

服务器端用法:

await auth.api.accountInfo({
  body: { accountId: "accountId" },
  headers: // 传递包含认证令牌的请求头
});

请求额外权限范围

有时您的应用可能在用户注册后需要额外的 OAuth 权限范围(例如,用于访问 GitHub 仓库或 Google Drive)。用户可能不希望一开始就授予过多权限,而是倾向于从最小权限开始,按需授予额外访问权限。

您可以通过使用同一提供商的 linkSocial 方法来请求额外权限范围。这将触发一个新的 OAuth 流程,在保持现有账户连接的同时请求额外权限。

const requestAdditionalScopes = async () => {
    await authClient.linkSocial({
        provider: "google",
        scopes: ["https://www.googleapis.com/auth/drive.file"],
    });
};

请确保您运行的是 Better Auth 1.2.7 或更高版本。早期版本(如 1.2.2)在尝试与现有提供商链接以获取额外权限时,可能会显示 "Social account already linked"(社交账户已链接)错误。

其他提供商配置

scope 访问请求的权限范围。例如,emailprofile

redirectURI 提供商的自定义重定向 URI。默认使用 /api/auth/callback/${providerName}

disableImplicitSignUp: 禁用隐式注册。要注册用户,需要在登录时将 requestSignUp 设置为 true

disableSignUp: 禁用新用户注册。

disableIdTokenSignIn: 禁用使用 ID 令牌进行登录。默认情况下,某些提供商(如 Google 和 Apple)会启用此功能。

verifyIdToken 用于验证 ID 令牌的自定义函数。

getUserInfo 用于从提供商获取用户信息的自定义函数。给定提供商返回的令牌,此函数应返回用户信息。

overrideUserInfoOnSignIn:一个布尔值,用于决定在用户登录时是否覆盖数据库中的用户信息。默认值为 false,表示在登录过程中不会覆盖用户信息。如果您希望在每次登录时更新用户信息,请将其设置为 true

refreshAccessToken:一个用于刷新令牌的自定义函数。此功能仅适用于内置的社交登录提供商(Google、Facebook、GitHub 等),目前不支持通过通用 OAuth 插件配置的自定义 OAuth 提供商。对于内置提供商,您可以根据需要提供一个自定义函数来刷新令牌。

mapProfileToUser:一个自定义函数,用于将提供商返回的用户信息映射到数据库中的用户对象。

如果您希望在用户对象中包含来自提供商配置文件的额外字段,或者想要更改默认的用户对象映射方式,此功能非常有用。

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  // 其他配置...
  socialProviders: {
    google: {
      clientId: "YOUR_GOOGLE_CLIENT_ID",
      clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
      mapProfileToUser: (profile) => {
        return {
          firstName: profile.given_name,
          lastName: profile.family_name,
        };
      },
    },
  },
});

Better Auth 中的 OAuth 工作原理

以下是用户选择身份验证提供商时的流程:

  1. 配置检查: 确保已配置必要的提供商详细信息(例如客户端 ID、密钥)。
  2. 状态生成: 生成状态令牌并保存到数据库中,用于 CSRF 保护。
  3. PKCE 支持: 如果适用,创建 PKCE 代码挑战和验证器以进行安全交换。
  4. 授权 URL 构建: 使用客户端 ID、重定向 URI、状态等参数构建提供商的授权 URL。回调 URL 通常遵循模式 /api/auth/callback/${providerName}
  5. 用户重定向:
    • 如果启用了重定向,用户将被重定向到提供商的登录页面。
    • 如果禁用了重定向,则返回授权 URL 供客户端处理重定向。

登录后流程

用户完成登录过程后,提供商会将其重定向回带有代码和状态的回调 URL。Better Auth 会处理后续步骤:

  1. 令牌交换: 将代码交换为访问令牌和用户信息。
  2. 用户处理:
    • 如果用户不存在,则创建新账户。
    • 如果用户已存在,则将其登录。
    • 如果用户在多个提供商处拥有多个账户,Better Auth 会根据您的配置将它们关联起来。了解更多关于账户关联的信息。
  3. 会话创建: 为用户创建新会话。
  4. 重定向: 用户被重定向到初始请求中指定的 URL 或 /

如果在过程中发生任何错误,Better Auth 会处理错误并将用户重定向到错误 URL(如果提供)或 callbackURL。并在查询字符串 ?error=... 中包含错误消息。

On this page