Repository navigation
Description
Description
When a browser opens a password-protected V2 web UI without credentials, the app shell now loads and boots unauthenticated while the event stream client reconnects to /api/event every second (reconnectDelay = 1_000 in packages/client/src/solid/connection.ts). Every reconnect returns 401 with WWW-Authenticate: Basic realm="Secure Area" (packages/server/src/middleware/authorization.ts). In Chromium-based browsers, each challenged request re-raises the native HTTP Basic auth prompt: while the user is typing the password, the dialog keeps being re-triggered roughly every second — it looks like screen flicker and keeps interrupting input. Firefox shows the prompt only once and is not visibly affected.
This became reachable with #46702 (merged 2026-09-02, 46c33630b7, "fix(server): authenticate only API requests"): authentication now applies only to /api, /api/*, and /openapi.json, so the HTML shell is public and the app starts issuing unauthenticated API requests before any credential exists. Before that commit, the document request itself was challenged once at navigation, so the native prompt appeared a single time before the app booted. The other two ingredients are older: the event-stream reconnect loop (dd296f7033, 2026-02-12, initially 250 ms) and the WWW-Authenticate challenge on API 401s (101566131d added it to UI fallback responses; 8cbc43fbb0, 2026-05-09 extended it to typed API 401s, which is what /api/event returns). The reconnect delay has been 1 s since 154f298fe9 (2026-08-13, #41930).
OpenCode version
v0.0.0-beta-18866
Steps to reproduce
- Run
opencode servein the foreground without a configured password (V2 generates a random one and printsserver password ...). - Open
http://127.0.0.1:<port>/in Chrome. The app shell renders, then the native Basic auth dialog appears. Firefox also shows the dialog, but only once — no flicker there. - Watch the network tab:
GET /api/eventfires about once per second, each returning401withWWW-Authenticate: Basic(alongside periodic/api/health401s). Measured with headless Chromium against the same server: 12 ×401on/api/eventin 12 s. Headless suppresses native auth prompts, so the dialog behavior needs a real browser. - Start typing the password into the native dialog: the dialog is re-triggered by the incoming 401s and input keeps getting interrupted.
Plugins
none
Operating System
Linux (Ubuntu), x64
Additional context
- Verified with a direct connection to the server (no proxy in between); an injected-CSS proxy behind a tunnel was ruled out as the cause.
- The server in this environment tracks the beta channel and already includes fix(server): authenticate only API requests #46702; the symptom is observed on every login on this build.
- Related closed issues: Repeated Auth Prompts when using Opencode Web from an authenticated Opencode Server #19920 (V1: repeated prompts from a WebSocket URL bug) and [Bug][Web] Basic auth causes 401 on /site.webmanifest and /global/event, then crashes with PasteTypeError #16493 (V1:
/global/event401 crash) predate the auth challenge; auth_token query param bypasses auth for HTML but not for subresource loads (CSS/JS) #31484 (static-asset 401s breakauth_token) shares the same challenge mechanism, just on a different request surface. - Browsers tested (real devices, Android 17 on Pixel 10 Build/CP2A.260805.005): Chrome 152.0.7977.64 re-fires the prompt roughly every second; Firefox 154.0.1 (Build #2016180583, GV 154.0.1-20260824154132) shows the prompt once with no flicker.
- Workaround: open the UI with
?auth_token=<URL-encoded base64 of "opencode:<password>">— the app then sends its ownAuthorizationheader and the native prompt never appears. URL-encoding matters: the app reads the token withURLSearchParams, which turns a bare+into a space.
Activity
holny commentedon Sep 4, 2026
I'd like to take this. The loop in
packages/client/src/solid/connection.tsretries everyreconnectDelay(1s) regardless of why the stream died, so a 401 withWWW-Authenticate: Basickeeps re-triggering the browser prompt every second. Plan: stop the auto-reconnect loop when the failure is a 401 (surface the auth requirement instead) or fall back to a long backoff — happy to go whichever way the maintainers prefer.holny commentedon Sep 9, 2026
Heads-up: the PR for this issue (#47204) was accidentally closed earlier today - its head fork got deleted unintentionally, which force-closed it. Re-filed as #48161 with the same commits. Sorry for the noise.
stickyburn commentedon Sep 20, 2026
As a workaround for now: use your {url}/api/info to login, then go back to the app and the login prompt is not shown.
ofrades commentedon Sep 25, 2026
Additional data point: the loop gets dramatically worse with more than one browser tab open, which matches the "constant reload / can't type" reports.
Each tab runs its own event-stream client, and every failed reconnect is a fresh challenged request:
GET /api/eventretried roughly once per second (v2.0.14reconnectDelay = 1_000, plus a 2s connect timeout), each 401 carryingwww-authenticate: Basic realm="Secure Area".pagehide/pageshowlifecycle handlers, producing another challenge on return.Also verified on a v2.0.16 standalone server: the shell and static assets are public (200) while
/api/*still returns 401 with the same challenge, so the loop is reachable without relying on the service-worker cache. Opening the new direct pairing link (/connect#<base64url credentials>) persists the credentials tolocalStorageand avoids the native prompt entirely; a backoff on the never-connected stream would close the remaining path.rosly commentedon Oct 17, 2026
Any progress?
neriousy commentedon Oct 20, 2026
Thanks for the detailed report! Starting in 2.0.17, browser background requests no longer trigger native Basic-auth dialogs, preventing the repeated prompts while signing in. Update with
opencode upgradeornpm i -g @opencode/cli@latest(desktop: update the app). Please reopen or comment if this still happens on that version or newer.