OAuth
Better Auth 内置支持 OAuth 2.0 和 OpenID Connect。这使你可以通过流行的 OAuth 提供商(如 Google、Facebook、GitHub 等)进行用户身份验证。
【Better Auth comes with built-in support for OAuth 2.0 and OpenID Connect. This allows you to authenticate users via popular OAuth providers like Google, Facebook, GitHub, and more.】
如果你希望使用的提供商未被直接支持,你可以使用通用 OAuth 插件进行自定义集成。
【If your desired provider isn't directly supported, you can use the Generic OAuth Plugin for custom integrations.】
配置社交提供商
【Configuring Social Providers】
要启用社交提供商,你需要提供该提供商的 clientId 和 clientSecret。
【To enable a social provider, you need to provide clientId and clientSecret for the provider.】
以下是配置 Google 作为提供商的示例:
【Here's an example of how to configure Google as a provider:】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
},
},
});用法
【Usage】
登录
【Sign In】
要使用社交提供商登录,你可以使用 signIn.social 函数配合 authClient,或在服务器端使用 auth.api。
【To sign in with a social provider, you can use the signIn.social function with the authClient or auth.api for server-side usage.】
// client-side usage
await authClient.signIn.social({
provider: "google", // or any other provider id
})// server-side usage
await auth.api.signInSocial({
body: {
provider: "google", // or any other provider id
},
});关联账户
【Link account】
要将账户关联到社交提供商,你可以使用 authClient 的 linkAccount 函数,或在服务器端使用 auth.api。
【To link an account to a social provider, you can use the linkAccount function with the authClient or auth.api for server-side usage.】
await authClient.linkSocial({
provider: "google", // or any other provider id
})服务器端使用:
【server-side usage:】
await auth.api.linkSocialAccount({
body: {
provider: "google", // or any other provider id
},
headers: // pass headers with authenticated token
});获取访问令牌
【Get Access Token】
要获取社交提供商的访问令牌,你可以使用 getAccessToken 函数配合 authClient 或用于服务器端的 auth.api。当你使用此端点时,如果访问令牌已过期,它将被刷新。
【To get the access token for a social provider, you can use the getAccessToken function with the authClient or auth.api for server-side usage. When you use this endpoint, if the access token is expired, it will be refreshed.】
const { accessToken } = await authClient.getAccessToken({
providerId: "google", // or any other provider id
accountId: "accountId", // optional, if you want to get the access token for a specific account
})服务器端使用:
【server-side usage:】
await auth.api.getAccessToken({
body: {
providerId: "google", // or any other provider id
accountId: "accountId", // optional, if you want to get the access token for a specific account
userId: "userId", // optional, if you don't provide headers with authenticated token
},
headers: // pass headers with authenticated token
});获取提供商提供的账户信息
【Get Account Info Provided by the provider】
要获取特定提供商的账户信息,你可以在服务器端使用 authClient 或 auth.api 调用 accountInfo 函数。
【To get provider specific account info you can use the accountInfo function with the authClient or auth.api for server-side usage.】
const info = await authClient.accountInfo({
accountId: "accountId", // here you pass in the provider given account id, the provider is automatically detected from the account id
})服务器端使用:
【server-side usage:】
await auth.api.accountInfo({
query: { accountId: "accountId" },
headers: // pass headers with authenticated token
});请求附加权限
【Requesting Additional Scopes】
有时,在用户已经注册之后,你的应用可能需要额外的 OAuth 范围(例如,访问 GitHub 仓库或 Google 云端硬盘)。用户可能不希望一开始就授予广泛的权限,而是更倾向于从最小权限开始,并根据需要授予额外访问权限。
【Sometimes your application may need additional OAuth scopes after the user has already signed up (e.g., for accessing GitHub repositories or Google Drive). Users may not want to grant extensive permissions initially, preferring to start with minimal permissions and grant additional access as needed.】
你可以通过对同一提供商使用 linkSocial 方法来请求额外的权限范围。这将触发一个新的 OAuth 流程,在保持现有账户连接的同时请求额外的权限范围。
【You can request additional scopes by using the linkSocial method with the same provider. This will trigger a new OAuth flow that requests the additional scopes while maintaining the existing account connection.】
const requestAdditionalScopes = async () => {
await authClient.linkSocial({
provider: "google",
scopes: ["https://www.googleapis.com/auth/drive.file"],
});
};请确保你正在运行 Better Auth 版本 1.2.7 或更高版本。较早的版本(如 1.2.2)在尝试使用现有提供商链接额外权限时,可能会显示“社交账户已绑定”错误。
通过 OAuth 流程传递附加数据
【Passing Additional Data Through OAuth Flow】
Better Auth 允许你在 OAuth 流程中传递额外的数据,而无需将其存储在数据库中。这对于跟踪推荐码、分析来源或其他在认证过程中需要处理但不需要保存的临时数据的场景非常有用。
【Better Auth allows you to pass additional data through the OAuth flow without storing it in the database. This is useful for scenarios like tracking referral codes, analytics sources, or other temporary data that should be processed during authentication but not persisted.】
在启动 OAuth 登录或账户关联时,传递附加数据:
【When initiating OAuth sign-in or account linking, pass the additional data:】
// Client-side: Sign in with additional data
await authClient.signIn.social({
provider: "google",
additionalData: {
referralCode: "ABC123",
source: "landing-page",
},
});
// Client-side: Link account with additional data
await authClient.linkSocial({
provider: "google",
additionalData: {
referralCode: "ABC123",
},
});
// Server-side: Sign in with additional data
await auth.api.signInSocial({
body: {
provider: "google",
additionalData: {
referralCode: "ABC123",
source: "admin-panel",
},
},
});在 Hook 中访问额外数据
【Accessing Additional Data in Hooks】
在 OAuth 回调期间,你可以通过 getOAuthState 在钩子中获取额外的数据。
【The additional data is available in your hooks during the OAuth callback through the getOAuthState.】
这通常适用于 /callback/:id 路径以及通用 OAuth 插件回调路径 (/oauth2/callback/:providerId)。
使用 before 钩子的示例:
【Example using a before hook:】
import { betterAuth } from "better-auth";
import { getOAuthState } from "better-auth/api";
export const auth = betterAuth({
// Other configurations...
hooks: {
after: [
{
matcher: () => true,
handler: async (ctx) => {
// Additional data is only available during OAuth callback
if (ctx.path === "/callback/:id") {
const additionalData = await getOAuthState<{
referralCode?: string;
source?: string;
}>();
if (additionalData) {
// IMPORTANT: Validate and sanitize the data before using it
// This data comes from the client and should not be trusted
// Example: Validate and process referral code
if (additionalData.referralCode) {
const isValidFormat = /^[A-Z0-9]{6}$/.test(additionalData.referralCode);
if (isValidFormat) {
// Verify the referral code exists in your database
const referral = await db.referrals.findByCode(additionalData.referralCode);
if (referral) {
// Safe to use the verified referral
await db.referrals.incrementUsage(referral.id);
}
}
}
// Track analytics (low-risk usage)
if (additionalData.source) {
await analytics.track("oauth_signin", {
source: additionalData.source,
userId: ctx.context.session?.user.id,
});
}
}
}
},
},
],
},
});使用数据库钩子的示例:
【Example using a database hook:】
// You can also access additional data in database hooks
databaseHooks: {
user: {
create: {
before: async (user, ctx) => {
if (ctx.path === "/callback/:id") {
const additionalData = await getOAuthState<{ referredFrom?: string }>();
if (additionalData?.referredFrom) {
return {
data: {
referredFrom: additionalData.referredFrom,
},
};
}
}
},
},
},
},默认情况下,OAuth 状态包括以下数据:
callbackURL- OAuth 流程的回调 URLcodeVerifier- OAuth 流程的代码验证器errorURL- OAuth 流程的错误 URLnewUserURL- OAuth 流程的新用户 URLlink- OAuth 流程的链接(邮箱和用户 ID)requestSignUp- 是否在 OAuth 流程中请求注册expiresAt- OAuth 状态的过期时间[key: string]:你在 OAuth 流程中传递的任何附加数据
提供者选项
【Provider Options】
范围
【scope】
访问请求的范围。例如,email 或 profile。
【The scope of the access request. For example, email or profile.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
scope: ["email", "profile"],
},
},
});重定向 URI
【redirectURI】
提供商的自定义重定向 URI。默认情况下,它使用 /api/auth/callback/${providerName}
【Custom redirect URI for the provider. By default, it uses /api/auth/callback/${providerName}】
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
redirectURI: "https://your-app.com/auth/callback",
},
},
});禁用注册
【disableSignUp】
禁止新用户注册。
【Disables sign-up for new users.】
禁用 ID 令牌登录
【disableIdTokenSignIn】
禁用使用 ID 令牌进行登录。默认情况下,对于 Google 和 Apple 等一些提供商,此功能是启用的。
【Disables the use of the ID token for sign-in. By default, it's enabled for some providers like Google and Apple.】
验证 ID 令牌
【verifyIdToken】
用于验证 ID 令牌的自定义函数。
【A custom function to verify the ID token.】
登录时覆盖用户信息
【overrideUserInfoOnSignIn】
一个布尔值,用于确定在登录时是否覆盖数据库中的用户信息。默认情况下,其值为 false,这意味着在登录期间不会覆盖用户信息。如果你希望每次用户登录时都更新其信息,请将其设置为 true。
【A boolean value that determines whether to override the user information in the database when signing in. By default, it is set to false, meaning that the user information will not be overridden during sign-in. If you want to update the user information every time they sign in, set this to true.】
将配置映射到用户
【mapProfileToUser】
一个自定义函数,用于将提供者返回的用户资料映射到你数据库中的用户对象。
【A custom function to map the user profile returned from the provider to the user object in your database.】
如果你的用户对象有额外的字段需要从提供者的资料中填充,这会很有用。或者如果你想改变用户对象默认的映射方式,也可以使用。
【Useful, if you have additional fields in your user object you want to populate from the provider's profile. Or if you want to change how by default the user object is mapped.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
mapProfileToUser: (profile) => {
return {
firstName: profile.given_name,
lastName: profile.family_name,
};
},
},
},
});刷新访问令牌
【refreshAccessToken】
用于刷新令牌的自定义函数。此功能仅支持内置社交提供商(Google、Facebook、GitHub 等),目前不支持通过通用 OAuth 插件配置的自定义 OAuth 提供商。对于内置提供商,如果需要,你可以提供自定义函数来刷新令牌。
【A custom function to refresh the token. This feature is only supported for built-in social providers (Google, Facebook, GitHub, etc.) and is not currently supported for custom OAuth providers configured through the Generic OAuth Plugin. For built-in providers, you can provide a custom function to refresh the token if needed.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
refreshAccessToken: async (token) => {
return {
accessToken: "new-access-token",
refreshToken: "new-refresh-token",
};
},
},
},
});客户端密钥
【clientKey】
你应用的客户端密钥。TikTok 社交提供商会使用它,而不是 clientId。
【The client key of your application. This is used by TikTok Social Provider instead of clientId.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
tiktok: {
clientKey: "YOUR_TIKTOK_CLIENT_KEY",
clientSecret: "YOUR_TIKTOK_CLIENT_SECRET",
},
},
});获取用户信息
【getUserInfo】
一个用于从提供者获取用户信息的自定义函数。这允许你覆盖默认的用户信息获取过程。
【A custom function to get user info from the provider. This allows you to override the default user info retrieval process.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
getUserInfo: async (token) => {
// Custom implementation to get user info
const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
headers: {
Authorization: `Bearer ${token.accessToken}`,
},
});
const profile = await response.json();
return {
user: {
id: profile.id,
name: profile.name,
email: profile.email,
image: profile.picture,
emailVerified: profile.verified_email,
},
data: profile,
};
},
},
},
});禁用隐式注册
【disableImplicitSignUp】
禁用新用户的隐式注册。当为该提供者设置为 true 时,需要在调用登录时将 requestSignUp 设置为 true 才能创建新用户。
【Disables implicit sign up for new users. When set to true for the provider, sign-in needs to be called with requestSignUp as true to create new users.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
disableImplicitSignUp: true,
},
},
});提示
【prompt】
用于授权代码请求的提示。这控制身份验证流程的行为。
【The prompt to use for the authorization code request. This controls the authentication flow behavior.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
prompt: "select_account", // or "consent", "login", "none", "select_account+consent"
},
},
});响应模式
【responseMode】
用于授权码请求的响应模式。这决定了授权响应的返回方式。
【The response mode to use for the authorization code request. This determines how the authorization response is returned.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
responseMode: "query", // or "form_post"
},
},
});禁用默认范围
【disableDefaultScope】
移除提供者的默认权限范围。默认情况下,提供者会包括某些权限范围,例如 email 和 profile。将此设置为 true 可以移除这些默认权限范围,仅使用你指定的权限范围。
【Removes the default scopes of the provider. By default, providers include certain scopes like email and profile. Set this to true to remove these default scopes and use only the scopes you specify.】
import { betterAuth } from "better-auth";
export const auth = betterAuth({
// Other configurations...
socialProviders: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET",
disableDefaultScope: true,
scope: ["https://www.googleapis.com/auth/userinfo.email"], // Only this scope will be used
},
},
});其他提供者配置
【Other Provider Configurations】
每个提供商可能有额外的选项,请查看具体提供商的文档以获取更多详细信息。
【Each provider may have additional options, check the specific provider documentation for more details.】