feat(auth): add opt-in local login bypass - #1042
Conversation
📝 WalkthroughWalkthroughAdds environment-controlled authentication bypass for trusted reverse-proxy deployments. Server middleware and routes use the first local user, while frontend authentication, WebSocket, shell, upload, and API behavior follow shared bypass configuration. Documentation, CLI output, and tests are updated. ChangesTrusted authentication bypass
Sequence Diagram(s)sequenceDiagram
participant Browser
participant AuthProvider
participant Server
participant UserDatabase
Browser->>AuthProvider: Initialize authentication
AuthProvider->>Server: Request status or onboarding state
Server->>UserDatabase: Retrieve first local user
UserDatabase-->>Server: Local user
Server-->>AuthProvider: Authenticated bypass user
AuthProvider->>Server: Open tokenless WebSocket
Server-->>Browser: Accept trusted connection
Possibly related issues
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/middleware/auth-bypass.test.js`:
- Around line 69-72: Update the verifyWebSocketClient invocation in the
auth-bypass test to pass isPlatform: false, ensuring it exercises the OSS/local
token extraction path while preserving the existing authenticateWebSocket
assertion.
- Line 17: Update the auth-bypass test’s verifyWebSocketClient invocation to
pass isPlatform: false, ensuring it exercises the OSS/local bypass path rather
than the platform branch.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5e9b1afa-7ec0-46a6-85bb-18d073d139c9
📒 Files selected for processing (16)
.env.exampleREADME.mdserver/cli.jsserver/constants/config.jsserver/index.jsserver/middleware/auth-bypass.test.jsserver/middleware/auth.jsserver/routes/auth.jsserver/routes/user.jssrc/components/auth/context/AuthContext.tsxsrc/components/auth/view/ProtectedRoute.tsxsrc/components/file-tree/hooks/useFileTreeUpload.tssrc/components/shell/utils/socket.tssrc/constants/config.tssrc/contexts/WebSocketContext.tsxsrc/utils/api.js
| const { closeConnection } = await import('../modules/database/connection.js'); | ||
| const { userDb } = await import('../modules/database/index.js'); | ||
| const { authenticateToken, authenticateWebSocket, getLocalBypassUser } = await import('./auth.js'); | ||
| const { verifyWebSocketClient } = await import('../modules/websocket/services/websocket-auth.service.ts'); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check test runner scripts for TypeScript loaders and search for similar .ts imports.
# Check package.json test scripts for tsx or node --experimental-strip-types
grep -i '"test"' package.json
# Check if other test files use .ts or .js for importing TypeScript files
rg "import\(.*\.ts['\"]\)" -g '*.js' || echo "No other .ts dynamic imports found in .js files."Repository: siteboon/claudecodeui
Length of output: 208
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package.json test-related scripts =="
grep -nE '"(test|test:|vitest|jest|mocha|tsx|node)"' package.json || true
echo
echo "== auth-bypass.test.js relevant lines =="
cat -n server/middleware/auth-bypass.test.js | sed -n '1,120p'
echo
echo "== websocket-auth.service.ts relevant symbols =="
rg -n "verifyWebSocketClient|authenticateWebSocket|TRUST_LOCAL_AUTH_BYPASS|isPlatform" server/modules/websocket/services/websocket-auth.service.tsRepository: siteboon/claudecodeui
Length of output: 3490
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package.json =="
cat -n package.json | sed -n '1,220p'Repository: siteboon/claudecodeui
Length of output: 8706
Use isPlatform: false in the WebSocket bypass test.
This test should exercise the OSS/local bypass path, not the platform branch.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/middleware/auth-bypass.test.js` at line 17, Update the auth-bypass
test’s verifyWebSocketClient invocation to pass isPlatform: false, ensuring it
exercises the OSS/local bypass path rather than the platform branch.
| const accepted = verifyWebSocketClient({ req: request }, { | ||
| isPlatform: true, | ||
| authenticateWebSocket, | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Test the OSS token extraction path, not platform mode.
The DISABLE_AUTH feature applies to the OSS/local mode. By passing isPlatform: true, this test forces the platform mode branch of verifyWebSocketClient, completely bypassing the OSS token extraction logic. Changing this to isPlatform: false ensures that the test correctly exercises the OSS path (which should extract a null token and verify that authenticateWebSocket still accepts the connection).
💚 Proposed fix
const accepted = verifyWebSocketClient({ req: request }, {
- isPlatform: true,
+ isPlatform: false,
authenticateWebSocket,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const accepted = verifyWebSocketClient({ req: request }, { | |
| isPlatform: true, | |
| authenticateWebSocket, | |
| }); | |
| const accepted = verifyWebSocketClient({ req: request }, { | |
| isPlatform: false, | |
| authenticateWebSocket, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/middleware/auth-bypass.test.js` around lines 69 - 72, Update the
verifyWebSocketClient invocation in the auth-bypass test to pass isPlatform:
false, ensuring it exercises the OSS/local token extraction path while
preserving the existing authenticateWebSocket assertion.
Source: Path instructions
Summary
DISABLE_AUTH/VITE_DISABLE_AUTHmode for deployments already protected by an authenticating reverse proxyConcrete use case
A Cloudflare Tunnel publishes CloudCLI while the CloudCLI service itself listens only on
127.0.0.1. Cloudflare Access protects the public hostname and requires Google OAuth (optionally restricted to a Google Workspace domain or selected users). Once Google authentication succeeds, Cloudflare forwards the request through the tunnel. CloudCLI should not prompt for a second username/password.The Access application must protect the entire hostname, including
/api,/ws, and/shell; the CloudCLI port must not be publicly reachable around the tunnel.Motivation
CloudCLI currently requires a second local login even after Cloudflare Access has authenticated the user with Google. A header-based trusted-proxy implementation was proposed in #798 / #799, but maintainers closed it as too complex for most users. This PR provides a smaller single-user opt-in mode for operators who deliberately keep the CloudCLI origin private behind the authenticating proxy.
Security
This mode is off by default. It does not inspect or trust client-provided identity headers and it does not create database users. Operators must first complete normal local setup, bind CloudCLI to a private address such as
127.0.0.1, configure Cloudflare Access to require Google authentication for the full hostname, and only then enable both flags. If no local user exists, REST requests return 503 and WebSocket authentication fails.Testing
npm run typecheckTSX_TSCONFIG_PATH=server/tsconfig.json node --import tsx --test server/middleware/auth-bypass.test.jsnpm run buildRelated: #798
Summary by CodeRabbit
/statusand onboarding status behavior when auth is disabled (including clearer failure when no local bypass user exists).