Skip to content

Add self-hosted Google auth#25

Merged
andrewzolotukhin merged 1 commit into
mainfrom
feat/self-hosted-google-auth
Jun 5, 2026
Merged

Add self-hosted Google auth#25
andrewzolotukhin merged 1 commit into
mainfrom
feat/self-hosted-google-auth

Conversation

@andrewzolotukhin

@andrewzolotukhin andrewzolotukhin commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Original request

The project is being prepared for open source/self-hosting. The current Google sign-in path depends on closed-source Cleverbrush Passport, which should remain available for Cleverbrush deployment, while self-hosters need a direct Google OAuth option using Auth.js-standard AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET. The README should document this thoroughly.

What changed

  • Added a direct Google sign-in API contract and handler at POST /api/auth/google/sign-in guarded by X-Xpenser-Web-Secret.
  • Refactored Google identity resolution so direct Auth.js Google OAuth and Passport both reuse the same google user and external_identities linking rules.
  • Added web auth-mode resolution with GOOGLE_SIGN_IN_MODE=auto|direct|passport|disabled.
  • Added Auth.js Google provider support for direct mode using AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET.
  • Kept the existing Passport PKCE flow, but only enables it when mode resolution selects Passport.
  • Marked the login page dynamic so runtime container auth env controls whether the Google button is shown in standalone Next.js builds.
  • Removed default references to https://auth.cleverbrush.com from self-hosted env/Compose defaults; PR environments explicitly set Passport mode.
  • Updated .env.example, Compose files, PR env docs/scripts, landing-page copy, and README authentication docs for self-hosted direct Google and private Passport.
  • Added focused tests for contracts, API handler trust boundary, shared Google identity resolution, and web auth-mode/profile mapping.

Reasoning

Direct Google OAuth should not introduce a second account model. The API already stores authProvider = 'google' users and external Google identity rows for Passport-created accounts, so the direct Auth.js path now feeds the same resolver. This preserves conflict behavior: verified Google email is required, local email/password accounts are not silently linked, and a user can only have one Google identity.

auto mode gives self-hosters a minimal setup: adding AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET enables direct Google sign-in, while leaving both Google and Passport unset hides the button and keeps email/password auth working. Cleverbrush deployments opt into Passport explicitly.

Screenshots / preview evidence

Preview URL: https://xpenser-pr-025.cleverbrush.com

Manual preview QA with agent-browser:

  • /login renders email/password login plus Sign in with Google in PR Passport mode.
  • Clicking Sign in with Google starts the existing Passport-to-Google redirect path and reaches Google OAuth with auth.cleverbrush.com as the OAuth app domain.
  • Seeded account login with test@cleverbrush.com reaches /dashboard and renders the authenticated dashboard.

Direct Google OAuth is covered by unit tests and docs because completing the real external Google OAuth callback in CI would require provider credentials and a user-controlled Google account.

Validation

Local validation performed from feat/self-hosted-google-auth:

  • npm run lint passed.
  • npm run typecheck passed.
  • npm test passed: 54 test files, 306 tests.
  • Focused test run passed for new/changed auth contract, API, and web helper tests.

GitHub checks on commit 85adc9741cad3ac653ad22b21cb913bd99e35316:

  • Lint and test passed.
  • Deploy PR environment passed.
  • Playwright e2e passed.

SigNoz verification after preview QA:

  • Traces: no recent error spans for xpenser-web-pr-25 or xpenser-api-pr-25; recent successful web and API spans are present.
  • Logs: no recent ERROR or FATAL logs for xpenser-web-pr-25 or xpenser-api-pr-25.
  • Metrics: nodejs.eventloop.utilization is present for xpenser-api-pr-25; web metrics were not listed in the metrics metadata, but web traces/logs were present and clean.

@andrewzolotukhin andrewzolotukhin temporarily deployed to pr-25 June 5, 2026 07:57 — with GitHub Actions Inactive
@andrewzolotukhin andrewzolotukhin force-pushed the feat/self-hosted-google-auth branch from 0769ed9 to 85adc97 Compare June 5, 2026 08:02
@andrewzolotukhin andrewzolotukhin temporarily deployed to pr-25 June 5, 2026 08:04 — with GitHub Actions Inactive
@andrewzolotukhin andrewzolotukhin merged commit e9716f2 into main Jun 5, 2026
4 checks passed
@andrewzolotukhin andrewzolotukhin deleted the feat/self-hosted-google-auth branch June 5, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant