OAuth
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.
If your desired provider isn't directly supported, you can use the Generic OAuth Plugin for custom integrations.
Configuring Social Providers
To enable a social provider, you need to provide clientId
and clientSecret
for the provider.
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
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
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
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
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({
body: { accountId: "accountId" },
headers: // pass headers with authenticated token
});
Requesting Additional Scopes
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.
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"],
});
};
Make sure you're running Better Auth version 1.2.7 or later. Earlier versions (like 1.2.2) may show a "Social account already linked" error when trying to link with an existing provider for additional scopes.
Provider Options
scope
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"],
},
},
});
redirectURI
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.
disableIdTokenSignIn
Disables the use of the ID token for sign-in. By default, it's enabled for some providers like Google and Apple.
verifyIdToken
A custom function to verify the ID token.
overrideUserInfoOnSignIn
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
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
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
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
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.