feat(auth): auto-hide OAuth buttons when secrets absent; add ALLOW_REGISTRATION toggle - #349
Merged
arozumenko merged 3 commits intoMay 22, 2026
Conversation
…GISTRATION toggle OAuth provider buttons (GitHub, Google) are now derived from server-side env vars at runtime via /api/auth/config, removing the error-prone manual NEXT_PUBLIC_SHOW_* flags. Setting ALLOW_REGISTRATION=false blocks sign-up at both the API layer (Better-Auth /sign-up/email and custom /register) and hides the register toggle in the UI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds runtime-driven auth UI configuration and a server-enforced registration toggle, removing brittle build-time flags and ensuring OAuth/registration availability reflects actual server secrets/config.
Changes:
- Add
GET /api/auth/configto expose enabled OAuth providers + registration availability to the client. - Update login UI to fetch auth config at runtime and conditionally render OAuth buttons + registration toggle.
- Enforce
ALLOW_REGISTRATION=falseserver-side for both Better-Auth email sign-up and the custom/api/auth/registerroute.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/app/login/page.tsx | Fetches /api/auth/config and conditionally renders OAuth + registration UI based on runtime config |
| web/src/app/api/auth/register/route.ts | Blocks custom registration endpoint when ALLOW_REGISTRATION=false |
| web/src/app/api/auth/config/route.ts | New endpoint returning provider enablement + registration flag |
| web/src/app/api/auth/[...all]/route.ts | Wraps Better-Auth POST handler to block /sign-up/email when registration disabled |
| web/.env.example | Removes NEXT_PUBLIC_SHOW_* flags, documents “blank secrets hide button”, adds ALLOW_REGISTRATION |
| .env.example | Documents “blank secrets hide button” and adds ALLOW_REGISTRATION |
Comments suppressed due to low confidence (1)
web/src/app/api/auth/[...all]/route.ts:1
- The registration block relies on
url.pathname.endsWith('/sign-up/email'). Requests with a trailing slash (e.g.,/sign-up/email/) won’t match and could bypass the intended 403. Normalize the path (e.g., strip trailing slashes) and/or compare against the exact expected pathname so the block is reliably enforced.
Comment on lines
+31
to
+35
| const [authConfig, setAuthConfig] = useState<{ | ||
| github: boolean; | ||
| google: boolean; | ||
| registrationEnabled: boolean; | ||
| } | null>(null); |
| )} | ||
|
|
||
| {(showGithub || showGoogle) && ( | ||
| {(authConfig?.github || authConfig?.google) && ( |
| </Divider> | ||
| <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, width: '100%' }}> | ||
| {showGithub && ( | ||
| {authConfig.github && ( |
| </Button> | ||
| )} | ||
| {showGoogle && ( | ||
| {authConfig.google && ( |
Comment on lines
+44
to
+50
| fetch('/api/auth/config') | ||
| .then((r) => r.json()) | ||
| .then((cfg) => { | ||
| setAuthConfig(cfg); | ||
| if (!cfg.registrationEnabled) setMode('login'); | ||
| }) | ||
| .catch(() => setAuthConfig({ github: false, google: false, registrationEnabled: true })); |
…cache header, optimistic UI, tests - Forward Next.js context param in catch-all POST (Better-Auth ignores it, but satisfies type contract) - Use exact pathname equality for sign-up block (prevents false matches on similar paths) - Add Cache-Control: public, max-age=300 to /api/auth/config (values are static per deployment) - Optimistic initial authConfig state so register toggle renders without layout shift - Integration tests for /api/auth/config and registration block in [...all]/route (12 cases) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment on lines
+46
to
+52
| fetch('/api/auth/config') | ||
| .then((r) => r.json()) | ||
| .then((cfg) => { | ||
| setAuthConfig(cfg); | ||
| if (!cfg.registrationEnabled) setMode('login'); | ||
| }) | ||
| .catch(() => {/* keep optimistic defaults on network error */}); |
Comment on lines
+11
to
+14
| const url = new URL(request.url); | ||
| if (process.env.ALLOW_REGISTRATION === 'false' && url.pathname === '/api/auth/sign-up/email') { | ||
| return NextResponse.json({ error: 'Registration is disabled' }, { status: 403 }); | ||
| } |
| GOOGLE_CLIENT_ID= | ||
| GOOGLE_CLIENT_ID= # Leave blank to hide "Sign in with Google" | ||
| GOOGLE_CLIENT_SECRET= | ||
| ALLOW_REGISTRATION=true # Set to false to disable self-service account creation |
…nt placement - Check r.ok before r.json() in config fetch; coerce fields to booleans so a non-2xx JSON error body can't corrupt authConfig state - Add mounted flag to config useEffect to prevent state update after unmount - Use message field (not error) in 403 response so handleRegister surfaces the real reason to the user via data.message - Move inline comments to their own lines in .env.example — trailing inline comments on assignment lines are treated as part of the value by some env parsers (dotenv, Docker Compose), causing non-empty CLIENT_ID values Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRETandGOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETare set. A newGET /api/auth/configendpoint exposes this to the client at runtime, replacing the unreliable manualNEXT_PUBLIC_SHOW_GITHUB/NEXT_PUBLIC_SHOW_GOOGLEflags (removed).ALLOW_REGISTRATION=falsein.envdisables self-service account creation — blocks Better-Auth's/sign-up/emailand the custom/registerroute (both return HTTP 403), and hides the "Create an account" toggle in the login UI. Default (var absent) keeps registration open.Test plan
GITHUB_CLIENT_ID/SECRETunset, GitHub button absent from login page; set both → button appearsALLOW_REGISTRATION=false→ "Create an account" link hidden,POST /api/auth/sign-up/emailreturns 403,POST /api/auth/registerreturns 403ALLOW_REGISTRATION=true(or unset) → registration works as before🤖 Generated with Claude Code