Skip to content

feat(auth): add opt-in local login bypass - #1042

Open
dongwook-chan wants to merge 2 commits into
siteboon:mainfrom
dongwook-chan:feat/disable-auth-behind-proxy
Open

feat(auth): add opt-in local login bypass#1042
dongwook-chan wants to merge 2 commits into
siteboon:mainfrom
dongwook-chan:feat/disable-auth-behind-proxy

Conversation

@dongwook-chan

@dongwook-chan dongwook-chan commented Jul 19, 2026

Copy link
Copy Markdown

Summary

  • add an opt-in DISABLE_AUTH / VITE_DISABLE_AUTH mode for deployments already protected by an authenticating reverse proxy
  • document the concrete Cloudflare Access setup: protect the CloudCLI hostname with a self-hosted Access application and a Google / Google Workspace allow policy before the tunnel reaches CloudCLI
  • bypass CloudCLI JWT checks consistently for REST, chat WebSocket, shell WebSocket, and file upload flows while reusing the existing single local user
  • fail closed when no local user exists and skip onboarding in bypass mode

Concrete 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 typecheck
  • TSX_TSCONFIG_PATH=server/tsconfig.json node --import tsx --test server/middleware/auth-bypass.test.js
  • npm run build

Related: #798

Summary by CodeRabbit

  • New Features
    • Added support for disabling built-in authentication when access control is handled by an upstream reverse proxy.
    • Updated quick start documentation and environment configuration for auth-bypass mode.
    • Auth-bypass now covers API access, WebSocket connections, and upload requests, using a local bypass user when available.
  • Bug Fixes
    • Improved /status and onboarding status behavior when auth is disabled (including clearer failure when no local bypass user exists).
    • Added stricter validation for refreshed authentication tokens.
  • Tests
    • Added automated tests for auth-bypass behavior, local-user requirements, and WebSocket access.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds 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.

Changes

Trusted authentication bypass

Layer / File(s) Summary
Configuration and deployment contract
.env.example, README.md, server/constants/config.js, src/constants/config.ts, server/cli.js
Adds DISABLE_AUTH, VITE_DISABLE_AUTH, and TRUST_LOCAL_AUTH_BYPASS, with deployment documentation and CLI visibility.
Server bypass authentication flow
server/middleware/auth.js, server/routes/*.js, server/index.js
Uses the first local user for trusted REST and WebSocket authentication, status, onboarding, and upgrade verification.
Frontend bypass propagation
src/components/auth/..., src/contexts/WebSocketContext.tsx, src/components/shell/..., src/components/file-tree/..., src/utils/api.js
Updates startup, protected routes, WebSocket URLs, shell connections, uploads, and API headers to follow trusted bypass mode; adds refreshed-token shape validation.
Bypass behavior validation
server/middleware/auth-bypass.test.js
Tests missing-user failures, local-user authentication, and tokenless WebSocket upgrades.

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
Loading

Possibly related issues

Possibly related PRs

Suggested reviewers: viper151, blackmammoth

Poem

I’m a bunny behind the proxy gate,
With local auth cleared from my plate.
WebSockets hop, tokens stay low,
The first user tells us where to go.
Config blooms, and tests cheer!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: an opt-in local login bypass for auth.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 27eaf01 and 35e7f60.

📒 Files selected for processing (16)
  • .env.example
  • README.md
  • server/cli.js
  • server/constants/config.js
  • server/index.js
  • server/middleware/auth-bypass.test.js
  • server/middleware/auth.js
  • server/routes/auth.js
  • server/routes/user.js
  • src/components/auth/context/AuthContext.tsx
  • src/components/auth/view/ProtectedRoute.tsx
  • src/components/file-tree/hooks/useFileTreeUpload.ts
  • src/components/shell/utils/socket.ts
  • src/constants/config.ts
  • src/contexts/WebSocketContext.tsx
  • src/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');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 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.ts

Repository: 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.

Comment on lines +69 to +72
const accepted = verifyWebSocketClient({ req: request }, {
isPlatform: true,
authenticateWebSocket,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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.

Suggested change
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants