---
title: OAuth
description: How Better Auth handles 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](/docs/plugins/generic-oauth) 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:

```ts title="auth.ts"
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.

```ts
await authClient.signIn.social({
  provider: "google", // or any other provider id
})
```

server-side usage:

```ts
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.

```ts
await authClient.linkSocial({
  provider: "google", // or any other provider id
})
```

server-side usage:

```ts
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.

```ts
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:

```ts
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.

```ts
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:

```ts
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.

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

<Callout>
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.
</Callout>

### Other Provider Configurations

**scope** The scope of the access request. For example, `email` or `profile`.

**redirectURI** Custom redirect URI for the provider. By default, it uses `/api/auth/callback/${providerName}`.

**disableImplicitSignUp:** Disables implicit sign-up. In order to sign up a user, `requestSignUp` needs to be set to `true` when signing in.

**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.

**getUserInfo** A custom function to fetch user information from the provider. Given the tokens returned from the provider, this function should return the user's information.

**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`.

**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.

**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.

```ts title="auth.ts"
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,
        };
      },
    },
  },
});
```

## How OAuth Works in Better Auth

Here's what happens when a user selects a provider to authenticate with:

1. **Configuration Check:** Ensure the necessary provider details (e.g., client ID, secret) are configured.
2. **State Generation:** Generate and save a state token in your database for CSRF protection.
3. **PKCE Support:** If applicable, create a PKCE code challenge and verifier for secure exchanges.
4. **Authorization URL Construction:** Build the provider's authorization URL with parameters like client ID, redirect URI, state, etc. The callback URL usually follows the pattern `/api/auth/callback/${providerName}`.
5. **User Redirection:**
   - If redirection is enabled, users are redirected to the provider's login page.
   - If redirection is disabled, the authorization URL is returned for the client to handle the redirection.

### Post-Login Flow

After the user completes the login process, the provider redirects them back to the callback URL with a code and state. Better Auth handles the rest:

1. **Token Exchange:** The code is exchanged for an access token and user information.
2. **User Handling:**
   - If the user doesn't exist, a new account is created.
   - If the user exists, they are logged in.
   - If the user has multiple accounts across providers, Better Auth links them based on your configuration. Learn more about [account linking](/docs/concepts/users-accounts#account-linking).
3. **Session Creation:** A new session is created for the user.
4. **Redirect:** Users are redirected to the specified URL provided during the initial request or `/`.

If any error occurs during the process, Better Auth handles it and redirects the user to the error URL (if provided) or the callbackURL. And it includes the error message in the query string `?error=...`.
