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:
- Builds a pre-filled
https://github.com/settings/applications/newURL (name, homepage, callback URL all filled in fromconfig.ts) and opens it in your browser. - You click "Register application", then "Generate a new client secret" — GitHub's UI, no way around it.
- Paste the Client ID and secret back into the terminal prompt.
- The script writes
GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET/VITE_GITHUB_CLIENT_IDinto 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.