# 629 OAUTH Providers 5201dc27

> OAuth Providers

- Skill: `tools-only/629-oauth-providers-5201dc27` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/629-oauth-providers-5201dc27`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/629-oauth-providers-5201dc27/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/tools-only/629-oauth-providers-5201dc27

---

# OAuth Providers

Better Auth provides built-in OAuth 2.0 support for social authentication. No plugins required.

## Supported Providers

GitHub, Google, Apple, Discord, Facebook, Microsoft, Twitter/X, Spotify, Twitch, LinkedIn, Dropbox, GitLab, and more.

## Basic OAuth Setup

### Server Configuration

```ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      // Optional: custom scopes
      scope: ["user:email", "read:user"]
    },
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      scope: ["openid", "email", "profile"]
    },
    discord: {
      clientId: process.env.DISCORD_CLIENT_ID!,
      clientSecret: process.env.DISCORD_CLIENT_SECRET!,
    }
  }
});
```

### Client Usage

```ts
import { authClient } from "@/lib/auth-client";

// Basic sign in
await authClient.signIn.social({
  provider: "github",
  callbackURL: "/dashboard"
});

// With callbacks
await authClient.signIn.social({
  provider: "google",
  callbackURL: "/dashboard",
  errorCallbackURL: "/error",
  newUserCallbackURL: "/welcome", // For first-time users
});
```

## Provider Configuration

### GitHub OAuth

1. Create OAuth App at https://github.com/settings/developers
2. Set Authorization callback URL: `http://localhost:3000/api/auth/callback/github`
3. Add credentials to `.env`:

```env
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
```

### Google OAuth

1. Create project at https://console.cloud.google.com
2. Enable Google+ API
3. Create OAuth 2.0 credentials
4. Add authorized redirect URI: `http://localhost:3000/api/auth/callback/google`
5. Add credentials to `.env`:

```env
GOOGLE_CLIENT_ID=your_client_id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your_client_secret
```

### Discord OAuth

1. Create application at https://discord.com/developers/applications
2. Add OAuth2 redirect: `http://localhost:3000/api/auth/callback/discord`
3. Add credentials:

```env
DISCORD_CLIENT_ID=your_client_id
DISCORD_CLIENT_SECRET=your_client_secret
```

### Apple Sign In

```ts
export const auth = betterAuth({
  socialProviders: {
    apple: {
      clientId: process.env.APPLE_CLIENT_ID!,
      clientSecret: process.env.APPLE_CLIENT_SECRET!,
      teamId: process.env.APPLE_TEAM_ID!,
      keyId: process.env.APPLE_KEY_ID!,
      privateKey: process.env.APPLE_PRIVATE_KEY!
    }
  }
});
```

### Microsoft/Azure AD

```ts
export const auth = betterAuth({
  socialProviders: {
    microsoft: {
      clientId: process.env.MICROSOFT_CLIENT_ID!,
      clientSecret: process.env.MICROSOFT_CLIENT_SECRET!,
      tenantId: process.env.MICROSOFT_TENANT_ID, // Optional: for specific tenant
    }
  }
});
```

### Twitter/X OAuth

```ts
export const auth = betterAuth({
  socialProviders: {
    twitter: {
      clientId: process.env.TWITTER_CLIENT_ID!,
      clientSecret: process.env.TWITTER_CLIENT_SECRET!,
    }
  }
});
```

## Custom OAuth Provider

Add custom OAuth 2.0 provider:

```ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  socialProviders: {
    customProvider: {
      clientId: process.env.CUSTOM_CLIENT_ID!,
      clientSecret: process.env.CUSTOM_CLIENT_SECRET!,
      authorizationUrl: "https://provider.com/oauth/authorize",
      tokenUrl: "https://provider.com/oauth/token",
      userInfoUrl: "https://provider.com/oauth/userinfo",
      scope: ["email", "profile"],
      // Map provider user data to Better Auth user
      mapProfile: (profile) => ({
        id: profile.id,
        email: profile.email,
        name: profile.name,
        image: profile.avatar_url
      })
    }
  }
});
```

## Account Linking

Link multiple OAuth providers to same user account.

### Server Setup

```ts
export const auth = betterAuth({
  account: {
    accountLinking: {
      enabled: true,
      trustedProviders: ["google", "github"] // Auto-link these providers
    }
  }
});
```

### Client Usage

```ts
// Link new provider to existing account
await authClient.linkSocial({
  provider: "google",
  callbackURL: "/profile"
});

// List linked accounts
const { data: session } = await authClient.getSession();
const accounts = session.user.accounts;

// Unlink account
await authClient.unlinkAccount({
  accountId: "account-id"
});
```

## Token Management

### Access OAuth Tokens

```ts
// Server-side
const session = await auth.api.getSession({
  headers: request.headers
});

const accounts = await auth.api.listAccounts({
  userId: session.user.id
});

// Get specific provider token
const githubAccount = accounts.find(a => a.providerId === "github");
const accessToken = githubAccount.accessToken;
const refreshToken = githubAccount.refreshToken;
```

### Refresh Tokens

```ts
// Manually refresh OAuth token
const newToken = await auth.api.refreshToken({
  accountId: "account-id"
});
```

### Use Provider API

```ts
// Example: Use GitHub token to fetch repos
const githubAccount = accounts.find(a => a.providerId === "github");

const response = await fetch("https://api.github.com/user/repos", {
  headers: {
    Authorization: `Bearer ${githubAccount.accessToken}`
  }
});

const repos = await response.json();
```

## Advanced OAuth Configuration

### Custom Scopes

```ts
export const auth = betterAuth({
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      scope: [
        "user:email",
        "read:user",
        "repo", // Access repositories
        "gist" // Access gists
      ]
    }
  }
});
```

### State Parameter

Better Auth automatically handles OAuth state parameter for CSRF protection.

```ts
// Custom state validation
export const auth = betterAuth({
  advanced: {
    generateState: async () => {
      // Custom state generation
      return crypto.randomUUID();
    },
    validateState: async (state: string) => {
      // Custom state validation
      return true;
    }
  }
});
```

### PKCE Support

Better Auth automatically uses PKCE (Proof Key for Code Exchange) for supported providers.

```ts
export const auth = betterAuth({
  socialProviders: {
    customProvider: {
      pkce: true, // Enable PKCE
      // ... other config
    }
  }
});
```

## Error Handling

### Client-Side

```ts
await authClient.signIn.social({
  provider: "github",
  errorCallbackURL: "/auth/error"
}, {
  onError: (ctx) => {
    console.error("OAuth error:", ctx.error);
    // Handle specific errors
    if (ctx.error.code === "OAUTH_ACCOUNT_ALREADY_LINKED") {
      alert("This account is already linked to another user");
    }
  }
});
```

### Server-Side

```ts
export const auth = betterAuth({
  callbacks: {
    async onOAuthError({ error, provider }) {
      console.error(`OAuth error with ${provider}:`, error);
      // Log to monitoring service
      await logError(error);
    }
  }
});
```

## Callback URLs

### Development

```
http://localhost:3000/api/auth/callback/{provider}
```

### Production

```
https://yourdomain.com/api/auth/callback/{provider}
```

**Important:** Add all callback URLs to OAuth provider settings.

## UI Components

### Sign In Button (React)

```tsx
import { authClient } from "@/lib/auth-client";

export function SocialSignIn() {
  const handleOAuth = async (provider: string) => {
    await authClient.signIn.social({
      provider,
      callbackURL: "/dashboard"
    });
  };

  return (
    <div className="space-y-2">
      <button onClick={() => handleOAuth("github")}>
        Sign in with GitHub
      </button>
      <button onClick={() => handleOAuth("google")}>
        Sign in with Google
      </button>
      <button onClick={() => handleOAuth("discord")}>
        Sign in with Discord
      </button>
    </div>
  );
}
```

## Best Practices

1. **Callback URLs**: Add all environments (dev, staging, prod) to OAuth app
2. **Scopes**: Request minimum scopes needed
3. **Token Storage**: Better Auth stores tokens securely in database
4. **Token Refresh**: Implement automatic token refresh for long-lived sessions
5. **Account Linking**: Enable for better UX when user signs in with different providers
6. **Error Handling**: Provide clear error messages for OAuth failures
7. **Provider Icons**: Use official brand assets for OAuth buttons
8. **Mobile Deep Links**: Configure deep links for mobile OAuth flows
9. **Email Matching**: Consider auto-linking accounts with same email
10. **Privacy**: Inform users what data you access from OAuth providers

## Common Issues

### Redirect URI Mismatch

Ensure callback URL in OAuth app matches exactly:
```
http://localhost:3000/api/auth/callback/github
```

### Missing Scopes

Add required scopes for email access:
```ts
scope: ["user:email"] // GitHub
scope: ["email"] // Google
```

### HTTPS Required

Some providers (Apple, Microsoft) require HTTPS callbacks. Use ngrok for local development:
```bash
ngrok http 3000
```

### CORS Errors

Configure CORS if frontend/backend on different domains:
```ts
export const auth = betterAuth({
  advanced: {
    corsOptions: {
      origin: ["https://yourdomain.com"],
      credentials: true
    }
  }
});
```

