Banata

Authentication

Social OAuth

Add social login with Google, GitHub, Apple, Microsoft, and 6 more providers — complete setup guides for each.

Banata Auth supports 10 social OAuth providers out of the box. Users can sign in with their existing accounts from these services, reducing friction and increasing sign-up conversion.


Supported Providers

ProviderConfig KeyOAuth TypeNotes
GooglegoogleOAuth 2.0 / OIDCMost common. Supports Google Workspace.
GitHubgithubOAuth 2.0Popular for developer tools.
AppleappleOAuth 2.0 / OIDCRequired for iOS App Store apps. Requires yearly key rotation.
MicrosoftmicrosoftOAuth 2.0 / OIDCSupports Azure AD. Requires tenantId.
FacebookfacebookOAuth 2.0Large consumer user base.
TwittertwitterOAuth 2.0Also known as X.
DiscorddiscordOAuth 2.0Popular for gaming and communities.
SpotifyspotifyOAuth 2.0For music-related apps.
TwitchtwitchOAuth 2.0 / OIDCFor streaming and gaming apps.
LinkedInlinkedinOAuth 2.0 / OIDCFor professional/B2B apps.

Configuration

Add social providers to your BanataAuthConfig:

typescript
// convex/banataAuth/auth.ts
function buildConfig(): BanataAuthConfig {
  return {
    appName: "My App",
    siteUrl: process.env.SITE_URL!,
    secret: process.env.BETTER_AUTH_SECRET!,
 
    authMethods: {
      emailPassword: true,   // Keep email/password alongside social
    },
 
    socialProviders: {
      google: {
        clientId: process.env.GOOGLE_CLIENT_ID!,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      },
      github: {
        clientId: process.env.GITHUB_CLIENT_ID!,
        clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      },
      // Add more providers as needed...
    },
  };
}

Setting Provider Credentials

OAuth credentials must be set on the Convex deployment (not in .env.local), since they're used by server-side Convex functions:

bash
# Google
npx convex env set GOOGLE_CLIENT_ID "your-google-client-id"
npx convex env set GOOGLE_CLIENT_SECRET "your-google-client-secret"
 
# GitHub
npx convex env set GITHUB_CLIENT_ID "your-github-client-id"
npx convex env set GITHUB_CLIENT_SECRET "your-github-client-secret"
 
# Apple
npx convex env set APPLE_CLIENT_ID "your-apple-service-id"
npx convex env set APPLE_CLIENT_SECRET "your-apple-client-secret"
 
# Microsoft
npx convex env set MICROSOFT_CLIENT_ID "your-microsoft-client-id"
npx convex env set MICROSOFT_CLIENT_SECRET "your-microsoft-client-secret"
npx convex env set MICROSOFT_TENANT_ID "your-tenant-id"

Provider Setup Guides

Google

  1. Go to the Google Cloud Console
  2. Create a new project (or select existing)
  3. Navigate to APIs & Services > Credentials
  4. Click Create Credentials > OAuth client ID
  5. Select Web application
  6. Add authorized redirect URI: http://localhost:3000/api/auth/callback/google
  7. Copy the Client ID and Client Secret
bash
npx convex env set GOOGLE_CLIENT_ID "123456789.apps.googleusercontent.com"
npx convex env set GOOGLE_CLIENT_SECRET "GOCSPX-..."
typescript
socialProviders: {
  google: {
    clientId: process.env.GOOGLE_CLIENT_ID!,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
  },
},

Production: Update the redirect URI to https://your-domain.com/api/auth/callback/google.

GitHub

  1. Go to GitHub Developer Settings
  2. Click New OAuth App
  3. Set Homepage URL: http://localhost:3000
  4. Set Authorization callback URL: http://localhost:3000/api/auth/callback/github
  5. Copy the Client ID
  6. Generate a new Client Secret
bash
npx convex env set GITHUB_CLIENT_ID "Ov23li..."
npx convex env set GITHUB_CLIENT_SECRET "your-secret"
typescript
socialProviders: {
  github: {
    clientId: process.env.GITHUB_CLIENT_ID!,
    clientSecret: process.env.GITHUB_CLIENT_SECRET!,
  },
},

Apple

Apple Sign-In requires more setup than other providers:

  1. Go to Apple Developer Portal
  2. Navigate to Certificates, Identifiers & Profiles > Identifiers
  3. Create a new App ID with Sign in with Apple enabled
  4. Create a Services ID (this is your clientId)
  5. Configure the Web Authentication domain and redirect URL: http://localhost:3000/api/auth/callback/apple
  6. Create a Key with Sign in with Apple enabled
  7. Generate the client secret using the key (Apple uses JWT-based secrets)
bash
npx convex env set APPLE_CLIENT_ID "com.myapp.auth"
npx convex env set APPLE_CLIENT_SECRET "your-generated-jwt-secret"
typescript
socialProviders: {
  apple: {
    clientId: process.env.APPLE_CLIENT_ID!,
    clientSecret: process.env.APPLE_CLIENT_SECRET!,
  },
},

Important: Apple client secrets expire after 6 months. You'll need to regenerate them periodically.

Microsoft (Azure AD)

  1. Go to the Azure Portal
  2. Click New registration
  3. Set redirect URI: http://localhost:3000/api/auth/callback/microsoft (Web platform)
  4. Note the Application (client) ID and Directory (tenant) ID
  5. Go to Certificates & secrets > New client secret
  6. Copy the secret value
bash
npx convex env set MICROSOFT_CLIENT_ID "your-app-id"
npx convex env set MICROSOFT_CLIENT_SECRET "your-secret-value"
npx convex env set MICROSOFT_TENANT_ID "your-tenant-id"
typescript
socialProviders: {
  microsoft: {
    clientId: process.env.MICROSOFT_CLIENT_ID!,
    clientSecret: process.env.MICROSOFT_CLIENT_SECRET!,
    tenantId: process.env.MICROSOFT_TENANT_ID!,  // Required for Microsoft
  },
},

Tenant ID options:

  • Specific tenant — Only users from that Azure AD tenant
  • "common" — Any Microsoft account (personal + work/school)
  • "organizations" — Work/school accounts only
  • "consumers" — Personal Microsoft accounts only

Facebook

  1. Go to Meta for Developers
  2. Create a new app (Consumer type)
  3. Add Facebook Login product
  4. Set Valid OAuth Redirect URIs: http://localhost:3000/api/auth/callback/facebook
  5. Go to Settings > Basic for App ID and App Secret
typescript
socialProviders: {
  facebook: {
    clientId: process.env.FACEBOOK_CLIENT_ID!,
    clientSecret: process.env.FACEBOOK_CLIENT_SECRET!,
  },
},

Twitter (X)

  1. Go to the Twitter Developer Portal
  2. Create a new project and app
  3. Enable OAuth 2.0
  4. Set Callback URL: http://localhost:3000/api/auth/callback/twitter
  5. Copy the Client ID and Client Secret
typescript
socialProviders: {
  twitter: {
    clientId: process.env.TWITTER_CLIENT_ID!,
    clientSecret: process.env.TWITTER_CLIENT_SECRET!,
  },
},

Discord

  1. Go to the Discord Developer Portal
  2. Create a new application
  3. Go to OAuth2 settings
  4. Add redirect: http://localhost:3000/api/auth/callback/discord
  5. Copy the Client ID and reset the Client Secret
typescript
socialProviders: {
  discord: {
    clientId: process.env.DISCORD_CLIENT_ID!,
    clientSecret: process.env.DISCORD_CLIENT_SECRET!,
  },
},

Spotify

  1. Go to the Spotify Developer Dashboard
  2. Create a new app
  3. Add redirect URI: http://localhost:3000/api/auth/callback/spotify
  4. Copy the Client ID and Client Secret
typescript
socialProviders: {
  spotify: {
    clientId: process.env.SPOTIFY_CLIENT_ID!,
    clientSecret: process.env.SPOTIFY_CLIENT_SECRET!,
  },
},

Twitch

  1. Go to the Twitch Developer Console
  2. Register a new application
  3. Set OAuth Redirect URL: http://localhost:3000/api/auth/callback/twitch
  4. Copy the Client ID and generate a Client Secret
typescript
socialProviders: {
  twitch: {
    clientId: process.env.TWITCH_CLIENT_ID!,
    clientSecret: process.env.TWITCH_CLIENT_SECRET!,
  },
},

LinkedIn

  1. Go to the LinkedIn Developer Portal
  2. Create a new app
  3. Under Auth, add redirect URL: http://localhost:3000/api/auth/callback/linkedin
  4. Request the Sign In with LinkedIn using OpenID Connect product
  5. Copy the Client ID and Client Secret
typescript
socialProviders: {
  linkedin: {
    clientId: process.env.LINKEDIN_CLIENT_ID!,
    clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
  },
},

Callback URL Pattern

All OAuth providers follow the same callback URL pattern:

typescript
{YOUR_SITE_URL}/api/auth/callback/{PROVIDER_ID}
EnvironmentExample
Local developmenthttp://localhost:3000/api/auth/callback/github
Productionhttps://myapp.com/api/auth/callback/github

The callback URL is handled by the catch-all route handler at /api/auth/[...all], which proxies the request to Convex where Better Auth processes the OAuth callback and creates/links the user account.


Client-Side Integration

Initiating Social Sign-In

typescript
import { authClient } from "@/lib/auth-client";
 
// Sign in with GitHub
await authClient.signIn.social({
  provider: "github",
  callbackURL: "/dashboard",  // Where to redirect after success
});
 
// Sign in with Google
await authClient.signIn.social({
  provider: "google",
  callbackURL: "/dashboard",
});

This redirects the user to the provider's OAuth consent page. After granting permission, they're redirected back to your callback URL, and then to the callbackURL you specified.

SocialButtons Component

Banata Auth ships a SocialButtons component that renders buttons for all configured providers:

tsx
import { SocialButtons } from "@banata-auth/react";
import { authClient } from "@/lib/auth-client";
 
// Define which providers to show
const providers = [
  { id: "google", label: "Google" },
  { id: "github", label: "GitHub" },
  { id: "apple", label: "Apple" },
];
 
export default function SignInPage() {
  return (
    <div>
      <h1>Sign In</h1>
 
      {/* Social login buttons */}
      <SocialButtons
        providers={providers}
        authClient={authClient}
        callbackURL="/dashboard"
      />
 
      {/* Divider */}
      <div>or</div>
 
      {/* Email/password form */}
      <SignInForm authClient={authClient} />
    </div>
  );
}

The SocialProvider interface:

typescript
interface SocialProvider {
  id: string;       // Provider ID: "google", "github", etc.
  label: string;    // Display name: "Google", "GitHub", etc.
  icon?: ReactNode; // Optional custom icon
}

Conditional Provider Configuration

You can conditionally enable providers based on whether credentials are available:

typescript
socialProviders:
  process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET
    ? {
        github: {
          clientId: process.env.GITHUB_CLIENT_ID,
          clientSecret: process.env.GITHUB_CLIENT_SECRET,
        },
        ...(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
          ? {
              google: {
                clientId: process.env.GOOGLE_CLIENT_ID,
                clientSecret: process.env.GOOGLE_CLIENT_SECRET,
              },
            }
          : {}),
      }
    : undefined,

This way, if credentials aren't set, the provider is simply not available — no errors thrown.


Account Linking

When a user signs in with a social provider and an account with the same email already exists (from email/password sign-up), Better Auth handles account linking:

  1. Auto-link — If the email is verified on both sides, the social account is automatically linked to the existing user.
  2. New account — If the email doesn't match any existing user, a new user is created.

The user can then sign in with either method (email/password or social).


How the OAuth Flow Works

Here's what happens under the hood when a user clicks "Sign in with GitHub":

typescript
1. BrowserPOST /api/auth/sign-in/social { provider: "github" }
2. Next.js route handlerProxies to Convex .site/api/auth/sign-in/social
3. Convex (Better Auth)Returns redirect to GitHub OAuth consent page
4. BrowserRedirected to github.com/login/oauth/authorize
5. UserGrants permission on GitHub
6. GitHubRedirects to /api/auth/callback/github?code=xxx
7. Next.js route handlerProxies to Convex .site/api/auth/callback/github
8. Convex (Better Auth)Exchanges code for tokens, creates/links user, creates session
9. BrowserRedirected to callbackURL (/dashboard) with session cookie set

The reverse proxy at /api/auth/[...all] uses redirect: "manual" to properly handle the redirect chain without the browser prematurely resolving redirects.


Audit Events

Social sign-ins generate these audit log events:

EventWhen
user.createdNew user created via social sign-in
session.createdSocial sign-in successful (new session)
account.linkedSocial account linked to existing user

Troubleshooting

"redirect_uri_mismatch" Error

The callback URL in your OAuth provider settings doesn't match the actual URL. Make sure:

  • Development: http://localhost:3000/api/auth/callback/{provider}
  • Production: https://your-domain.com/api/auth/callback/{provider}

"Access Denied" After Granting Permission

  1. Check that the provider's Client Secret is correctly set on Convex: npx convex env list
  2. Check that the provider is included in your socialProviders config.
  3. For Microsoft, make sure tenantId is set.

User Created Without Name/Email

Some providers don't return all user fields. Check the provider's scope settings to ensure you're requesting the right permissions (e.g., email scope for Google).


What's Next