GitHub OAuth Setup

GitHub OAuth Setup

Sign-in with GitHub uses src/server/auth.ts's github social provider (better-auth). Each deployed domain (and localhost) needs its own GitHub OAuth App, because the callback URL is matched exactly, an app registered for https://example.com/api/auth/callback/github will not accept a login started from http://localhost:3000.

Why this needs a wizard, not a CLI flag

GitHub has no REST API or gh CLI command to create an OAuth App, only GitHub Apps support the scriptable manifest-based creation flow; OAuth Apps are web-UI-only to register. gh api can't reach an endpoint that doesn't exist.

make github.oauth.setup automates everything around that one manual step:

  1. Builds a pre-filled https://github.com/settings/applications/new URL (name, homepage, callback URL all filled in from config.ts) and opens it in your browser.
  2. You click "Register application", then "Generate a new client secret", GitHub's UI, no way around it.
  3. Paste the Client ID and secret back into the terminal prompt.
  4. The script writes GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET / VITE_GITHUB_CLIENT_ID into the right env file.

Usage

make github.oauth.setup ENV=local   # -> .env, callback http://localhost:3000/api/auth/callback/github
make github.oauth.setup ENV=prod    # -> .env.production, callback https://<config.domainName>/api/auth/callback/github

ENV defaults to local if omitted. Run both once per domain you deploy to, a fresh clone scaffolded to a new domain needs its own pair of apps, not a reused one.

After ENV=prod: the change only lands in the local .env.production file. Ship it with make deploy.env and restart the app service so auth.ts picks up the new credentials.

Why per-domain, not one shared app

A single OAuth App's callback URL list can technically hold multiple URLs, but keeping prod and local as separate apps means a leaked/rotated local dev secret never touches the production app, and GitHub's "third-party access" screen for users shows the real app name/domain instead of a shared one covering unrelated environments.

Scopes

auth.ts requests user:email (login identity) and repo (deploy/git-integration features that read the user's repos). If a downstream project doesn't need repo access, drop repo from the scope array in auth.ts before running the wizard, GitHub shows requested scopes on the consent screen but doesn't let you change them per-login after the app is registered.