GenerateSaaS

Social OAuth

Enable Google, GitHub, Facebook, Discord, and X sign-in via config.auth.socialProviders.

Social login is powered by Better Auth in the @repo/auth package and gated entirely by config.auth.socialProviders. Each id you list renders a sign-in button; list nothing and the whole social block disappears.

How it works

  • config.auth.socialProviders is an array of provider ids (google, github, facebook, discord, x). It holds the providers you chose at init (it may be empty), and only those buttons render; .env.example seeds credentials for those same providers.
  • A provider registers server-side only when both its env vars are set - the socialProviders block in packages/auth/src/config.ts spreads each one in conditionally.
  • The Nuxt AuthSocialButtons.vue component reads the same array and renders one button per id, labelled from SOCIAL_PROVIDERS_META via $t.
  • Clicking a button signs in through authClient.signIn.social.

Supported providers

Each provider needs a client ID + secret in your environment. Ids and env vars come from SOCIAL_PROVIDERS_META (packages/config/src/social-providers.ts):

ProviderIdEnv vars
GooglegoogleGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
GitHubgithubGITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
FacebookfacebookFACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET
DiscorddiscordDISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET
XxTWITTER_CLIENT_ID, TWITTER_CLIENT_SECRET

The X provider uses the legacy TWITTER_* env prefix, not X_*. Set TWITTER_CLIENT_ID / TWITTER_CLIENT_SECRET.

Enable a provider

Add the id to config.auth.socialProviders:

packages/config/src/index.ts
auth: {
  socialProviders: ["google", "github"], // buttons render in this order
},

Set the matching env vars. .env.example seeds placeholders for the providers you selected at init; vars for any other provider are still valid, just not listed - copy the names from the table above.

.env
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...

Set the OAuth app's redirect URL in the provider's developer console to <API_URL>/auth/callback/<provider> - Better Auth's baseURL is ${API_URL}/auth, and API_URL already ends in /api. With the default API_URL=http://localhost:3000/api that resolves to http://localhost:3000/api/auth/callback/google.

For X, the callback <provider> segment is twitter (Better Auth's underlying provider name), e.g. <API_URL>/auth/callback/twitter - not .../callback/x.

An id can be in config.auth.socialProviders but missing its env vars - the button still renders, yet sign-in fails because the provider was never registered server-side. Keep the array and your env in sync.

Removing a provider

  • Drop the id from config.auth.socialProviders and its button disappears instantly - no component changes needed.
  • The array order is the display order of the buttons.
  • An empty array hides the entire social-login section, leaving only email/password (and any enabled passkey button).

Frequently asked questions

Why does my button do nothing / error on click? Its env vars are unset, so the provider never registered server-side. The button renders off the config array, but registration needs both *_CLIENT_ID and *_CLIENT_SECRET set.

Why is the X provider using TWITTER_* env vars? The provider id is x, but Better Auth's underlying provider is still named twitter - so the credentials use the TWITTER_CLIENT_ID / TWITTER_CLIENT_SECRET names.

Can I add a provider not in the list? The five ids in SOCIAL_PROVIDERS_META are wired end-to-end. Adding others means extending that metadata plus the socialProviders block in packages/auth/src/config.ts.

On this page