Skip to content

[Bug]: iOS LAN gateway connects are forced to wss, and bootstrap-only setup codes fail onboarding #47887

Description

@styles01

Bug type

Regression (worked before, now fails)

Summary

I tracked a cluster of iOS gateway onboarding failures to four related issues.

Steps to reproduce

  • Manual LAN connect to ws://192.168.x.x:18789 or ws://openclaw.local:18789 hangs/fails before auth.
  • The iOS app discovers the gateway and HTTP works, but WebSocket onboarding via setup code hangs.
  • Manually entering the shared gateway auth token works immediately.

Expected behavior

Connects properly

Actual behavior

iOS was silently rewriting local-network ws:// inputs to wss://

  • apps/ios/Sources/Gateway/GatewayConnectionController.swift:164
  • apps/ios/Sources/Gateway/GatewayConnectionController.swift:711
  • The manual path treated any non-loopback host as TLS-required.
  • That means valid LAN hosts like 192.168.x.x, .local, Tailscale addresses, and .ts.net were being upgraded to wss:// before auth, which breaks plain-LAN gateways.
  • Local fix: allow plaintext for local-network hosts and log TLS overrides / trust-probe failures.
  1. Bootstrap setup keys are single-use, but iOS opens two sockets in parallel
  • apps/ios/Sources/Model/NodeAppModel.swift:1713
  • apps/ios/Sources/Model/NodeAppModel.swift:1722
  • src/infra/device-bootstrap.ts:110
  • src/gateway/server/ws-connection/message-handler.ts:766
  • iOS starts both operator and node sessions with the same bootstrap token.
  • The bootstrap token is consumed on first successful verification.
  • One socket can hit PAIRING_REQUIRED, while the other immediately gets AUTH_BOOTSTRAP_TOKEN_INVALID.
  • Result: setup-code onboarding stalls.
  1. The QR/setup-code generator was forcing the broken bootstrap path
  • src/pairing/setup-code.ts:15
  • src/pairing/setup-code.ts:376
  • The generator emitted only { url, bootstrapToken }, even though the iOS parser already supports token and password.
  • That means QR onboarding could not use the same shared gateway credential that already works when entered manually.
  • Local fix: emit the resolved shared token or password in the setup payload instead of bootstrap-only auth.
  1. Mixed auth preferred bootstrap over password
  • apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayChannel.swift:516
  • src/gateway/client.ts:518
  • If both bootstrapToken and password were present, the client still chose bootstrap auth first.
  • That makes mixed payloads and stale stored bootstrap state behave incorrectly.
  • Local fix: suppress bootstrap auth whenever an explicit password is present.

Why I think this is the right fix

  • Manual shared-token auth succeeds against the same gateway.
  • Raw HTTP and WebSocket reachability were both healthy.
  • The failing path was specifically setup-code/bootstrap onboarding.

Suggested maintainer actions

  • Keep the iOS LAN ws:// fix.
  • Stop generating bootstrap-only setup codes when shared gateway auth is available.
  • Keep password-over-bootstrap precedence in both Swift and TypeScript clients.
  • Longer-term: revisit whether single-use bootstrap tokens are compatible with the current multi-socket onboarding flow at all.

Validated locally with

  • targeted TypeScript tests for setup-code generation and gateway auth selection
  • Swift GatewayChannelConnectTests
  • successful iOS app build and device install

OpenClaw version

2026.3.13

Operating system

Macos 12

Install method

No response

Model

OpenAI 5.4

Provider / routing chain

openclaw LAN

Config file / key location

No response

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

Metadata

Metadata

Labels

bugSomething isn't workingregressionBehavior that previously worked and now fails

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions