feat(auth): GitHub OAuth login (opt-in) - #28
Conversation
Add GitHub as a better-auth social provider, gated behind GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET (mirrors the existing Google OAuth wiring) on both the Cloudflare (apps/main) and Node self-host (apps/main-node) runtimes. The Console Login page shows a "Continue with GitHub" button when /auth-info advertises the provider. Co-authored-by: duyet <me@duyet.net> Co-authored-by: duyetbot <bot@duyet.net>
|
Warning Review limit reached
Next review available in: 52 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (10)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces optional GitHub OAuth login support across the console, main-node, and main apps, updating the configuration, environment variables, documentation, and login UI to support GitHub authentication alongside Google. The review feedback suggests improving the user experience by adding error handling and loading state management to the social sign-in actions, as well as disabling the login buttons during active requests to prevent duplicate submissions.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const handleGithub = async () => { | ||
| await authClient.signIn.social({ | ||
| provider: "github", | ||
| callbackURL: nextUrl, | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Social sign-in actions like authClient.signIn.social can fail before redirecting (e.g., due to network issues or misconfiguration). Adding error handling and managing the loading state will prevent silent failures and improve the user experience. You should also apply this same pattern to handleGoogle.
| const handleGithub = async () => { | |
| await authClient.signIn.social({ | |
| provider: "github", | |
| callbackURL: nextUrl, | |
| }); | |
| }; | |
| const handleGithub = async () => { | |
| setError(""); | |
| setLoading(true); | |
| try { | |
| const { error } = await authClient.signIn.social({ | |
| provider: "github", | |
| callbackURL: nextUrl, | |
| }); | |
| if (error) { | |
| setError(error.message || "Failed to sign in with GitHub"); | |
| } | |
| } catch (err: any) { | |
| setError(err?.message || "An unexpected error occurred"); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; |
| <button | ||
| onClick={handleGithub} | ||
| className="w-full flex items-center justify-center gap-2 px-4 py-2.5 border border-border rounded-md text-sm text-fg hover:bg-bg-surface transition-colors duration-[var(--dur-quick)] ease-[var(--ease-soft)]" | ||
| > |
There was a problem hiding this comment.
Disable the button and reduce its opacity when loading is true to prevent multiple clicks or form submissions while the redirect is in progress.
<button
onClick={handleGithub}
disabled={loading}
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 border border-border rounded-md text-sm text-fg hover:bg-bg-surface transition-colors duration-[var(--dur-quick)] ease-[var(--ease-soft)] disabled:opacity-50"
>
Reconcile with #27 (website), #28 (GitHub OAuth), #29 (trusted-proxy auth). Kept the incoming feature code and applied the @duyet/oma-* rename to all newly-added old-scope references (trusted-proxy.ts + tests, apps/main-node, packages/auth, packages/auth-config, docs/self-host.md, deploy-website.yml, package.json filters). Collapsed apps/web wrangler routes to the single oma.duyet.net custom domain. Co-authored-by: duyet <me@duyet.net> Co-authored-by: duyetbot <bot@duyet.net>
What / why
Adds GitHub as a
better-authsocial provider for the Console, mirroringthe existing Google OAuth wiring exactly — same opt-in-via-env pattern, same
runtime coverage (Cloudflare
apps/mainand Node self-hostapps/main-node), same Console button placement.packages/auth-config—buildBetterAuth()acceptsgithubClientId/githubClientSecret; registersgithubonsocialProvidersonly whenboth are set (else no-op, matches Google's behavior exactly).
apps/main/src/auth-config.ts+apps/main/src/index.ts(Cloudflare) —reads
GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRETfromEnv, advertises"github"on/auth-infowhen configured.apps/main-node/src/index.ts(Node self-host, both Postgres and SQLitebranches) — same env vars, same
/auth-infoadvertisement.packages/shared/src/env.ts— newGITHUB_CLIENT_ID?/GITHUB_CLIENT_SECRET?fields (deliberately distinct from the existing
GITHUB_OAUTH_CLIENT_IDpair, which is unrelated — that one is for MCP-server/integration OAuth,
not Console login).
apps/console/src/pages/Login.tsx— shows "Continue with GitHub" next to"Continue with Google" when
/auth-infoadvertises the provider; wiredvia
authClient.signIn.social({ provider: "github" })..env.example,docs/self-host.md,docs/deployment.md— document thenew env vars and GitHub OAuth App setup steps.
When the env vars are unset, GitHub OAuth is simply not registered — zero
behavior change for existing deployments.
Env vars
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETBoth must be set together — setting only one leaves GitHub unregistered
(same rule as the existing Google pair).
GitHub OAuth App setup
(or under an org's settings, for an org-owned app).
PUBLIC_BASE_URL(e.g.
https://console.example.com).${PUBLIC_BASE_URL}/auth/callback/github— better-auth mounts the social-provider callback at
/callback/:idunder the
/authbasePath.GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET(.envfor Docker self-host, orwrangler secret putfor the Cloudflare deploy).Full walkthrough in
docs/self-host.md(new "GitHub OAuth login (optional)"section).
Acceptance
GITHUB_CLIENT_ID+GITHUB_CLIENT_SECRETset → better-authregisters
githubas a social provider;/auth-infoadvertises it;Console shows "Continue with GitHub".
githubentry, no/auth-infochange, nobutton, no crash — behavior identical to before this PR.
apps/main) and Node self-host(
apps/main-node).packages/auth-config/src/index.test.ts) assertsregistration/non-registration for both the paired-set and
only-one-set cases, plus independence from the Google provider.
pnpm typecheckpasses (root + node pass +apps/console).Test plan
Per instructions, the full
pnpm build/ fullpnpm testsuite was notrun in this change — only the new test's own file and
pnpm typecheck.🤖 Generated with Claude Code