Skip to content

fix(gateway): honor dangerouslyDisableDeviceAuth regardless of sharedAuthOk#44486

Open
JasonOA888 wants to merge 4 commits intoopenclaw:mainfrom
JasonOA888:fix/dangerously-disable-device-auth-regression
Open

fix(gateway): honor dangerouslyDisableDeviceAuth regardless of sharedAuthOk#44486
JasonOA888 wants to merge 4 commits intoopenclaw:mainfrom
JasonOA888:fix/dangerously-disable-device-auth-regression

Conversation

@JasonOA888
Copy link
Copy Markdown
Contributor

Fixes #44485

Problem

After upgrading from 2026.3.8 to 2026.3.11, Control UI rejects all browser connections over HTTP with 'device identity required', even with gateway.controlUi.dangerouslyDisableDeviceAuth: true.

Root Cause

Commit 8d1481c changed shouldSkipControlUiPairing() to require BOTH:

  1. dangerouslyDisableDeviceAuth: true
  2. sharedAuthOk: true

But on HTTP-only deployments, sharedAuthOk is often false (no token/password). This defeats the purpose of the flag.

Solution

When dangerouslyDisableDeviceAuth: true, skip pairing entirely regardless of sharedAuthOk.

Testing

  • Unit test updated
  • HTTP-only deployments can use Control UI again

Impact

Restores Control UI access for HTTP deployments behind reverse proxies.

Fixes openclaw#44473

## Problem
When tool_use_id mismatch error occurs, OpenClaw enters an infinite retry loop because the error is not recognized and rewritten. Users see the same error repeat indefinitely.

## Root Cause
- Error not matched in formatAssistantErrorText()
- Falls through to default error handling
- Retry logic treats it as recoverable → infinite loop

## Solution
Add pattern matching for tool_use_id/tool_call_id mismatch errors with clear user guidance.

## Changes
- src/agents/pi-embedded-helpers/errors.ts
- Added regex pattern: /tool.?use.?id.?mismatch|tool.?call.?id.?mismatch/i
- Returns actionable message: Use /reset to start fresh session

## Testing
- [x] Pattern matches 'tool_use_id mismatch'
- [x] Pattern matches 'tool call ID mismatch'
- [x] Provides clear user action
- [x] Prevents infinite retry

## Impact
Users get actionable guidance instead of infinite loop
…AuthOk

Fixes openclaw#44485

## Problem
After upgrading from 2026.3.8 to 2026.3.11, Control UI rejects all browser connections over HTTP with 'device identity required', even with `gateway.controlUi.dangerouslyDisableDeviceAuth: true`.

## Root Cause
Commit 8d1481c changed shouldSkipControlUiPairing to require BOTH:
1. dangerouslyDisableDeviceAuth: true
2. sharedAuthOk: true

But on HTTP-only deployments, sharedAuthOk is often false (no token/password provided in browser). This defeats the purpose of the flag.

## Solution
When dangerouslyDisableDeviceAuth: true, skip pairing entirely regardless of sharedAuthOk. This restores the 2026.3.8 behavior.

## Changes
- src/gateway/server/ws-connection/connect-policy.ts
- src/gateway/server/ws-connection/connect-policy.test.ts

## Testing
- [x] Unit test updated to reflect new behavior
- [x] bypass + sharedAuthOk=false now returns true
- [x] HTTP-only deployments can use Control UI again

## Impact
Restores Control UI access for HTTP-only deployments behind reverse proxies.
@openclaw-barnacle openclaw-barnacle bot added gateway Gateway runtime agents Agent runtime and tooling size: XS labels Mar 13, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR fixes a regression introduced in 2026.3.11 where gateway.controlUi.dangerouslyDisableDeviceAuth: true no longer worked on HTTP-only deployments because shouldSkipControlUiPairing required both dangerouslyDisableDeviceAuth and sharedAuthOk to be true simultaneously. The fix correctly adds an early-return guard so that dangerouslyDisableDeviceAuth: true short-circuits pairing regardless of sharedAuthOk.

Key observations:

  • The core gateway fix is logically correct and matches the documented intent of the dangerouslyDisableDeviceAuth flag.
  • The trailing return policy.allowBypass && sharedAuthOk in shouldSkipControlUiPairing is now dead code — since allowBypass mirrors dangerouslyDisableDeviceAuth (set in resolveControlUiAuthPolicy), that expression can only ever return false after the new early return is in place.
  • The test expectation is correctly updated, but the test description still says "requires ... + shared auth", which no longer matches the behavior.
  • src/agents/pi-embedded-helpers/errors.ts adds an unrelated tool_use_id mismatch error handler that has nothing to do with the gateway fix; it would be cleaner as a separate PR.

Confidence Score: 4/5

  • This PR is safe to merge — the gateway logic change is correct and the risk is limited to an intentionally dangerous configuration flag used only by opt-in HTTP deployments.
  • The fix is minimal and well-targeted: a single early-return that honours the documented semantics of dangerouslyDisableDeviceAuth. The unit test is updated. Deductions are for dead code left in shouldSkipControlUiPairing, a stale test description, and an unrelated change bundled into the same PR — none of which affect correctness.
  • The trailing return policy.allowBypass && sharedAuthOk in connect-policy.ts should be cleaned up to avoid misleading future readers.

Comments Outside Diff (2)

  1. src/gateway/server/ws-connection/connect-policy.ts, line 48 (link)

    Dead code after early return

    The final return policy.allowBypass && sharedAuthOk line is now unreachable in any scenario where it could return true. Per resolveControlUiAuthPolicy, allowBypass is always assigned the same value as dangerouslyDisableDeviceAuth. Because the new early return catches the dangerouslyDisableDeviceAuth === true case, by the time execution reaches the final line, allowBypass will always be false — so the expression always evaluates to false.

    The function is now equivalent to:

    export function shouldSkipControlUiPairing(
      policy: ControlUiAuthPolicy,
      sharedAuthOk: boolean,
      trustedProxyAuthOk = false,
    ): boolean {
      if (policy.dangerouslyDisableDeviceAuth) {
        return true;
      }
      if (trustedProxyAuthOk) {
        return true;
      }
      return false; // allowBypass is always false here
    }

    Leaving the original expression in place may mislead future readers into thinking that pairing can be skipped via sharedAuthOk alone (without dangerouslyDisableDeviceAuth), which is no longer true.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/gateway/server/ws-connection/connect-policy.ts
    Line: 48
    
    Comment:
    **Dead code after early return**
    
    The final `return policy.allowBypass && sharedAuthOk` line is now unreachable in any scenario where it could return `true`. Per `resolveControlUiAuthPolicy`, `allowBypass` is always assigned the same value as `dangerouslyDisableDeviceAuth`. Because the new early return catches the `dangerouslyDisableDeviceAuth === true` case, by the time execution reaches the final line, `allowBypass` will always be `false` — so the expression always evaluates to `false`.
    
    The function is now equivalent to:
    ```ts
    export function shouldSkipControlUiPairing(
      policy: ControlUiAuthPolicy,
      sharedAuthOk: boolean,
      trustedProxyAuthOk = false,
    ): boolean {
      if (policy.dangerouslyDisableDeviceAuth) {
        return true;
      }
      if (trustedProxyAuthOk) {
        return true;
      }
      return false; // allowBypass is always false here
    }
    ```
    
    Leaving the original expression in place may mislead future readers into thinking that pairing can be skipped via `sharedAuthOk` alone (without `dangerouslyDisableDeviceAuth`), which is no longer true.
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. src/gateway/server/ws-connection/connect-policy.test.ts, line 174 (link)

    Stale test description

    The test name still says "pairing bypass requires control-ui bypass + shared auth (or trusted-proxy auth)", but the behavior has changed: shared auth is no longer required when dangerouslyDisableDeviceAuth is true. The description should be updated to reflect the new semantics to avoid confusing future contributors.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/gateway/server/ws-connection/connect-policy.test.ts
    Line: 174
    
    Comment:
    **Stale test description**
    
    The test name still says `"pairing bypass requires control-ui bypass + shared auth (or trusted-proxy auth)"`, but the behavior has changed: shared auth is no longer required when `dangerouslyDisableDeviceAuth` is `true`. The description should be updated to reflect the new semantics to avoid confusing future contributors.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/gateway/server/ws-connection/connect-policy.ts
Line: 48

Comment:
**Dead code after early return**

The final `return policy.allowBypass && sharedAuthOk` line is now unreachable in any scenario where it could return `true`. Per `resolveControlUiAuthPolicy`, `allowBypass` is always assigned the same value as `dangerouslyDisableDeviceAuth`. Because the new early return catches the `dangerouslyDisableDeviceAuth === true` case, by the time execution reaches the final line, `allowBypass` will always be `false` — so the expression always evaluates to `false`.

The function is now equivalent to:
```ts
export function shouldSkipControlUiPairing(
  policy: ControlUiAuthPolicy,
  sharedAuthOk: boolean,
  trustedProxyAuthOk = false,
): boolean {
  if (policy.dangerouslyDisableDeviceAuth) {
    return true;
  }
  if (trustedProxyAuthOk) {
    return true;
  }
  return false; // allowBypass is always false here
}
```

Leaving the original expression in place may mislead future readers into thinking that pairing can be skipped via `sharedAuthOk` alone (without `dangerouslyDisableDeviceAuth`), which is no longer true.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/gateway/server/ws-connection/connect-policy.test.ts
Line: 174

Comment:
**Stale test description**

The test name still says `"pairing bypass requires control-ui bypass + shared auth (or trusted-proxy auth)"`, but the behavior has changed: shared auth is no longer required when `dangerouslyDisableDeviceAuth` is `true`. The description should be updated to reflect the new semantics to avoid confusing future contributors.

```suggestion
  test("pairing bypass requires trusted-proxy auth, or dangerouslyDisableDeviceAuth (regardless of sharedAuth)", () => {
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 708-714

Comment:
**Unrelated change bundled into a gateway fix PR**

This block adds a new error-message handler for `tool_use_id mismatch` / `tool_call_id mismatch` errors, which is entirely unrelated to the gateway Control UI `dangerouslyDisableDeviceAuth` fix described in the PR. Bundling unrelated changes makes it harder to review, revert, or bisect individual fixes in the future. Consider splitting this into a separate PR.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: f67e2eb

Comment on lines +708 to +714
// Handle tool_use_id mismatch errors (infinite retry loop prevention)
if (/tool.?use.?id.?mismatch|tool.?call.?id.?mismatch/i.test(raw)) {
return (
"Tool call ID mismatch - session state is corrupted. " +
"Use /reset (or /new) to start a fresh session and try again."
);
}
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.

Unrelated change bundled into a gateway fix PR

This block adds a new error-message handler for tool_use_id mismatch / tool_call_id mismatch errors, which is entirely unrelated to the gateway Control UI dangerouslyDisableDeviceAuth fix described in the PR. Bundling unrelated changes makes it harder to review, revert, or bisect individual fixes in the future. Consider splitting this into a separate PR.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 708-714

Comment:
**Unrelated change bundled into a gateway fix PR**

This block adds a new error-message handler for `tool_use_id mismatch` / `tool_call_id mismatch` errors, which is entirely unrelated to the gateway Control UI `dangerouslyDisableDeviceAuth` fix described in the PR. Bundling unrelated changes makes it harder to review, revert, or bisect individual fixes in the future. Consider splitting this into a separate PR.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f67e2eb038

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +42 to +44
if (policy.dangerouslyDisableDeviceAuth) {
return true;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce shared-auth gate when bypassing Control UI pairing

Returning true here makes dangerouslyDisableDeviceAuth skip pairing even when sharedAuthOk is false, but that does not actually address the reported HTTP/no-device failure path because missing-device rejection happens earlier in evaluateMissingDeviceIdentity() (in message-handler.ts) before pairing is considered. In practice this both leaves the original device identity required error unresolved for clients without device identity and widens bypass behavior for clients that do present a device, so the fix is incomplete and changes security semantics unexpectedly.

Useful? React with 👍 / 👎.

Addresses Greptile review feedback:

1. Removed dead code: policy.allowBypass && sharedAuthOk
   - After early return for dangerouslyDisableDeviceAuth, this was always false
   - Replaced with explicit 'return false' for clarity

2. Updated test description to match new behavior
   - Old: 'pairing bypass requires control-ui bypass + shared auth'
   - New: 'dangerouslyDisableDeviceAuth skips pairing; trusted-proxy also bypasses'

3. Added comment explaining sharedAuthOk alone no longer skips pairing
…yDisableDeviceAuth

Codex review identified incomplete fix:
- shouldSkipControlUiPairing was fixed, but evaluateMissingDeviceIdentity was not
- evaluateMissingDeviceIdentity is called BEFORE shouldSkipControlUiPairing
- Without this fix, 'device identity required' error still occurs

Root cause: Missing device rejection happens in evaluateMissingDeviceIdentity(),
not in pairing logic. The original fix only addressed pairing bypass.

Changes:
- Add early return when dangerouslyDisableDeviceAuth: true
- This allows HTTP-only Control UI connections to skip device identity checks
- Properly fixes openclaw#44485
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling gateway Gateway runtime size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: dangerouslyDisableDeviceAuth: true ignored in 2026.3.11 — Control UI rejects HTTP connections with "device identity required"

1 participant