Skip to content

web: native Basic auth prompt re-fires every second while entering credentials #47062

Closed

Description

@RateteDev

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

  1. Run opencode serve in the foreground without a configured password (V2 generates a random one and prints server password ...).
  2. 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.
  3. Watch the network tab: GET /api/event fires about once per second, each returning 401 with WWW-Authenticate: Basic (alongside periodic /api/health 401s). Measured with headless Chromium against the same server: 12 × 401 on /api/event in 12 s. Headless suppresses native auth prompts, so the dialog behavior needs a real browser.
  4. 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

Activity

  1. holny commented on Sep 4, 2026

    @holny
    Contributor

    I'd like to take this. The loop in packages/client/src/solid/connection.ts retries every reconnectDelay (1s) regardless of why the stream died, so a 401 with WWW-Authenticate: Basic keeps 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.

  2. holny commented on Sep 9, 2026

    @holny
    Contributor

    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.

  3. stickyburn commented on Sep 20, 2026

    @stickyburn

    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.

  4. ofrades commented on Sep 25, 2026

    @ofrades

    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:

    • 1 tab: GET /api/event retried roughly once per second (v2.0.14 reconnectDelay = 1_000, plus a 2s connect timeout), each 401 carrying www-authenticate: Basic realm="Secure Area".
    • 2 tabs: ~2 challenged requests per second total (one loop per tab), so the native prompt is re-raised almost continuously and the credential form cannot be filled.
    • Switching between tabs also stops/starts the stream via the pagehide/pageshow lifecycle 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 to localStorage and avoids the native prompt entirely; a backoff on the never-connected stream would close the remaining path.

  5. rosly commented on Oct 17, 2026

    @rosly

    Any progress?

  6. neriousy commented on Oct 20, 2026

    @neriousy
    Member

    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 upgrade or npm i -g @opencode/cli@latest (desktop: update the app). Please reopen or comment if this still happens on that version or newer.

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions