Skip to main content
Better Hub uses Better Auth with GitHub OAuth for authentication. Users sign in with their GitHub account to access the platform.

GitHub OAuth Setup

Create a GitHub OAuth App

1

Navigate to GitHub Developer Settings

2

Configure the OAuth App

Fill in the application details:
  • Application name: Better Hub (Development) or your app name
  • Homepage URL: http://localhost:3000 (development) or your production URL
  • Authorization callback URL: http://localhost:3000/api/auth/callback/github
For production, use your production domain:
https://yourdomain.com/api/auth/callback/github
3

Get your credentials

After creating the app, copy the Client ID and generate a Client Secret.
4

Add to environment variables

Add the credentials to your .env file:
GITHUB_CLIENT_ID=your_client_id_here
GITHUB_CLIENT_SECRET=your_client_secret_here
Create separate OAuth Apps for development and production environments. Never use production credentials in development.

GitHub Scopes

Better Hub requests minimal permissions by default and allows users to grant additional scopes as needed: Default scopes (required on sign-in):
  • read:user - Read user profile information
  • user:email - Access user email addresses
  • public_repo - Access public repositories
Additional scopes (optional, requested per-feature):
  • repo - Full repository access (for private repos)
  • workflow - GitHub Actions workflow permissions
Scopes are configured in apps/web/src/lib/auth.ts:108.

Better Auth Configuration

Generate Auth Secret

Better Auth requires a secret for encrypting sessions and tokens:
openssl rand -hex 16
Add this to your .env file:
BETTER_AUTH_SECRET=your_generated_secret_here
The BETTER_AUTH_SECRET must be:
  • At least 32 characters long
  • Cryptographically random
  • Different in each environment
  • Never committed to version control

Application URLs

Set the base URL for your application:
BETTER_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_APP_URL=http://localhost:3000
These URLs must match the OAuth callback URL configured in GitHub.

Auth Configuration Details

Better Hub’s authentication is configured in apps/web/src/lib/auth.ts. Key features:

Database Adapter

Better Auth uses Prisma with PostgreSQL:
database: prismaAdapter(prisma, {
  provider: "postgresql",
})

Plugins Enabled

dash
plugin
Activity tracking and analytics dashboard
sentinel
plugin
Security monitoring and rate limiting
admin
plugin
Admin user management and impersonation
stripe
plugin
Payment and subscription management (optional, enabled when Stripe is configured)
oAuthProxy
plugin
OAuth proxy for Vercel preview deployments
patSignIn
plugin
Custom plugin for GitHub Personal Access Token authentication

Session Configuration

Sessions are cached in encrypted cookies for performance:
session: {
  cookieCache: {
    enabled: true,
    maxAge: 60 * 60 * 24 * 7, // 7 days
    strategy: "jwe", // JSON Web Encryption
  },
}

OAuth Token Encryption

GitHub OAuth tokens are encrypted before storage:
account: {
  encryptOAuthTokens: true,
  storeAccountCookie: true,
  updateAccountOnSignIn: true, // Refreshes scopes
}

Trusted Origins

CORS is configured for these origins:
  • https://www.better-hub.com (production)
  • https://better-hub-*-better-auth.vercel.app (Vercel previews)
  • https://beta.better-hub.com (beta environment)
Configure additional origins in apps/web/src/lib/auth.ts:123.

User Model

Better Auth extends the base user model with custom fields:
githubPat
string
GitHub Personal Access Token (optional, for additional API access)
onboardingDone
boolean
default:false
Tracks whether user has completed onboarding flow
Full user schema is defined in apps/web/prisma/schema.prisma:11-39.

Session Management

Server-Side Session Access

Use getServerSession() to access the session in server components and API routes:
import { getServerSession } from "@/lib/auth";

export default async function Page() {
  const session = await getServerSession();
  
  if (!session) {
    return <div>Not authenticated</div>;
  }
  
  return <div>Welcome, {session.user.name}</div>;
}

Session Data Structure

The session object includes:
{
  user: {
    id: string;
    name: string;
    email: string;
    image: string;
    githubPat?: string;
    onboardingDone: boolean;
  },
  session: {
    id: string;
    expiresAt: Date;
    userId: string;
  },
  githubUser: {
    login: string;
    accessToken: string;
    // ...other GitHub user data
  }
}

GitHub API Integration

The session automatically includes GitHub user data and access token, cached in Redis for 1 hour:
const cached = await redis.get(`github_user:${token}`);
See implementation in apps/web/src/lib/auth.ts:18-28.

Multi-Environment Setup

Development

1

Create development OAuth App

Create a GitHub OAuth App with callback URL: http://localhost:3000/api/auth/callback/github
2

Configure .env

GITHUB_CLIENT_ID=dev_client_id
GITHUB_CLIENT_SECRET=dev_client_secret
BETTER_AUTH_SECRET=$(openssl rand -hex 16)
BETTER_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_APP_URL=http://localhost:3000

Staging/Preview

For Vercel preview deployments, use the OAuth proxy:
...(process.env.VERCEL
  ? [oAuthProxy({ productionURL: "https://www.better-hub.com" })]
  : []),
This proxies OAuth through production, so preview deployments use production OAuth credentials.

Production

1

Create production OAuth App

Create a separate GitHub OAuth App with your production domain callback URL
2

Set production environment variables

Configure variables in your hosting platform (Vercel, Railway, etc.)
3

Verify trusted origins

Ensure your production domain is in the trustedOrigins array

Security Best Practices

Critical security requirements:
  1. Never commit .env files to version control
  2. Use different OAuth apps per environment
  3. Rotate secrets regularly
  4. Enable 2FA on GitHub accounts with OAuth apps
  5. Monitor failed authentication attempts via Sentinel plugin

IP Address Tracking

Better Auth tracks IP addresses for security:
advanced: {
  ipAddress: {
    ipAddressHeaders: ["x-vercel-forwarded-for", "x-forwarded-for"],
  },
}

Rate Limiting

The Sentinel plugin provides automatic rate limiting on authentication endpoints.

Troubleshooting

OAuth Callback URL Mismatch

Error: redirect_uri_mismatch Solution: Ensure the callback URL in your GitHub OAuth App exactly matches:
{BETTER_AUTH_URL}/api/auth/callback/github

Invalid Client Error

Error: invalid_client Solution: Verify GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET are correct and from the same OAuth App.

Session Not Persisting

Symptoms: Users logged out on page refresh Solutions:
  • Verify BETTER_AUTH_SECRET is set and at least 32 characters
  • Check browser cookie settings (must allow cookies)
  • Ensure BETTER_AUTH_URL matches the actual application URL

GitHub API Rate Limiting

Symptoms: getServerSession() returns partial data Solution: Redis caching helps, but GitHub has rate limits. Consider:
  • Using a GitHub Personal Access Token for higher limits
  • Implementing additional caching layers
  • Requesting only necessary data

Advanced Configuration

Custom Profile Mapping

Customize how GitHub profile data maps to user records:
mapProfileToUser(profile) {
  return {
    githubLogin: profile.login,
    // Add custom mappings here
  };
}
See apps/web/src/lib/auth.ts:109-113.

Enable User Deletion

User self-service account deletion is enabled:
user: {
  deleteUser: {
    enabled: true,
  },
}
This allows users to delete their accounts via the settings page.

Stripe Integration

When Stripe environment variables are configured, the Stripe plugin automatically:
  • Creates Stripe customers on signup
  • Grants signup credits
  • Manages subscriptions
See the Environment Variables guide for Stripe configuration details.