You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Web] Infinite Authentication Loop when opening Terminal in v1.2.25 #17376
After configuring a username and password, attempting to open the Terminal in OpenCode Web results in a continuous authentication prompt. Even after entering the correct credentials, the login dialog reappears immediately, preventing access to the terminal interface.
InShot_20260313_223240715.mp4
Plugins
No response
OpenCode version
v1.2.25
Steps to reproduce
[CLI] OPENCODE_SERVER_USERNAME=username OPENCODE_SERVER_PASSWORD=yourpassword opencode web
[Browser] localhost:4096
Enter username/password
Click terminal icon
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Reacted by Michael "Mike" Ferris, Matesanz, David Christ, Christian, Alvaro, Kim taek seo, Willian Luis Zuqui, Kevin Adam, c25423, catslashbin and 4 more
Basically, when the websocket tries to open, it does not contain the Basic Authorization header, causing a 401 which then causes the browser to clear its existing Basic Auth from memory and request a new one.
Repro Steps
open opencode in a private/incognito window
type in username password
open any project
open the terminal (this causes the 401 loop)
Workaround, set the username password in the server settings (on top of the basic auth request). I honestly didn't even know this was a thing...
I'll ask OpenCode to post the findings on my research here in a moment
Reacted by konmeo, MwumLi, tired_i, Alain P Igban and Haris Houlis
The infinite authentication loop is caused by the terminal's WebSocket connection explicitly sending wrong credentials, which poisons the browser's HTTP Basic Auth cache.
The Bug
When the web app opens a terminal, terminal.tsx constructs a WebSocket URL with explicit credentials:
For web browser access (not desktop), server.current.http has no stored username or password — the user authenticated via the browser's native Basic Auth dialog, and those credentials are never captured by the app. So this evaluates to:
url.username = "opencode"
url.password = "" (empty string)
The WebSocket URL becomes ws://opencode:@host:port/pty/.../connect, which explicitly tells the browser to send Authorization: Basic b3BlbmNvZGU6 (base64 of opencode:) — overriding the browser's cached (correct) Basic Auth credentials.
The server rejects this (empty password ≠ real password) with 401 Unauthorized. This 401 on the WebSocket handshake poisons the browser's auth cache for the entire origin, causing all subsequent requests to fail and triggering the infinite re-authentication loop.
Why regular HTTP requests work
The PUT request to create the PTY (PUT /pty/{id}) works fine because it uses the SDK's fetch(), which inherits the browser's cached Basic Auth credentials automatically. Only the WebSocket is broken because it explicitly overrides credentials via the URL.
Regression History
PR #13813 (1bb857417, Feb 18) introduced the latent bug by removing a conditional guard:
-// BEFORE: Only set WebSocket creds when desktop app provides them-if (window.__OPENCODE__?.serverPassword) {- url.username = "opencode"- url.password = window.__OPENCODE__?.serverPassword-}+// AFTER: Always sets creds unconditionally — empty for web browser+url.username = server.current?.http.username ?? ""+url.password = server.current?.http.password ?? ""
Before this change, the web browser path left the WebSocket URL without explicit credentials, so the browser's auth cache handled authentication correctly.
PR #17061 (c9c0318e0, Mar 12) then turned this latent bug into an active one by changing the username fallback from "" to "opencode". With both username and password as empty strings, some browsers treat the URL as having no credentials and still use the auth cache. With username="opencode" and password="", the browser now explicitly sends wrong credentials, guaranteeing the 401.
Suggested Fix
Only set explicit WebSocket credentials when the server connection actually has stored credentials (i.e., the user entered them in the app's "Add Server" dialog, not via the browser's native auth prompt):
This lets the browser's Basic Auth cache handle WebSocket authentication transparently for web browser users — the same way it already works for all regular HTTP requests (PUT, GET, SSE, etc.).
I haven't been able to test the fix locally because my local setup doesn't trigger the basic auth request (the browser doesn't ask for credentials when the url of the page doesn't match the url of the server)
If someone can help me set it up properly to test it I could confirm and open a PR.
Otherwise, if someone is setup to test it and wants to open the PR go right ahead, I just hope my investigation helps :)
Any idea when this will be fixed ? I really love opencode, and I was thinking I could use the web served version on my vps just like how @adamdotdevin said in a podcast I watched the other day.
A temporary solution before this is fixed (at least works for me), is that set the user_name as opencode but set the password personal. And when you use the web app, never touch the terminal button (try any other terminals instead, like ssh).
A temporary solution before this is fixed (at least works for me), is that set the user_name as opencode but set the password personal. And when you use the web app, never touch the terminal button (try any other terminals instead, like ssh).
This is what I'm doing currently, with termux, but I'd like to only use one app instead of switching back and forth. Other than that, what an amazing app opencode is
I experience this problem in 1.3.12 on Linux under different circumstances, which may help narrow down the cause.
I do not have authentication configured for opencode. Instead, my opencode instance is behind an NGINX proxy which has authentication. Opening the terminal results in an authentication loop.
This just happened to me. Was running 1.2.x and accidentally clicked terminal, got infinite auth loop. I tried terminating opencode on the server and when it came back up it was still looping. Then upgraded to 1.14.28, still looping. Tried starting it with no password, still looping.
Activity
github-actions commentedon Mar 13, 2026
This issue might be a duplicate of existing issues. Please check:
maddestructor commentedon Mar 13, 2026
My colleague and I are having the same issue on our side when using basic auth on an opencode server.
Cellule commentedon Mar 13, 2026
I've narrowed it down to something happening when the web app tries to open a connection to the terminal
opencode/packages/app/src/components/terminal.tsx
Lines 512 to 521 in f2d3a4c
Basically, when the websocket tries to open, it does not contain the Basic Authorization header, causing a 401 which then causes the browser to clear its existing Basic Auth from memory and request a new one.
Repro Steps
Workaround, set the username password in the server settings (on top of the basic auth request). I honestly didn't even know this was a thing...

I'll ask OpenCode to post the findings on my research here in a moment
Cellule commentedon Mar 13, 2026
Root Cause Analysis
The infinite authentication loop is caused by the terminal's WebSocket connection explicitly sending wrong credentials, which poisons the browser's HTTP Basic Auth cache.
The Bug
When the web app opens a terminal,
terminal.tsxconstructs a WebSocket URL with explicit credentials:For web browser access (not desktop),
server.current.httphas no storedusernameorpassword— the user authenticated via the browser's native Basic Auth dialog, and those credentials are never captured by the app. So this evaluates to:url.username = "opencode"url.password = ""(empty string)The WebSocket URL becomes
ws://opencode:@host:port/pty/.../connect, which explicitly tells the browser to sendAuthorization: Basic b3BlbmNvZGU6(base64 ofopencode:) — overriding the browser's cached (correct) Basic Auth credentials.The server rejects this (empty password ≠ real password) with 401 Unauthorized. This 401 on the WebSocket handshake poisons the browser's auth cache for the entire origin, causing all subsequent requests to fail and triggering the infinite re-authentication loop.
Why regular HTTP requests work
The PUT request to create the PTY (
PUT /pty/{id}) works fine because it uses the SDK'sfetch(), which inherits the browser's cached Basic Auth credentials automatically. Only the WebSocket is broken because it explicitly overrides credentials via the URL.Regression History
PR #13813 (
1bb857417, Feb 18) introduced the latent bug by removing a conditional guard:Before this change, the web browser path left the WebSocket URL without explicit credentials, so the browser's auth cache handled authentication correctly.
PR #17061 (
c9c0318e0, Mar 12) then turned this latent bug into an active one by changing the username fallback from""to"opencode". With both username and password as empty strings, some browsers treat the URL as having no credentials and still use the auth cache. Withusername="opencode"andpassword="", the browser now explicitly sends wrong credentials, guaranteeing the 401.Suggested Fix
Only set explicit WebSocket credentials when the server connection actually has stored credentials (i.e., the user entered them in the app's "Add Server" dialog, not via the browser's native auth prompt):
This lets the browser's Basic Auth cache handle WebSocket authentication transparently for web browser users — the same way it already works for all regular HTTP requests (PUT, GET, SSE, etc.).
Cellule commentedon Mar 14, 2026
I haven't been able to test the fix locally because my local setup doesn't trigger the basic auth request (the browser doesn't ask for credentials when the url of the page doesn't match the url of the server)
If someone can help me set it up properly to test it I could confirm and open a PR.
Otherwise, if someone is setup to test it and wants to open the PR go right ahead, I just hope my investigation helps :)
boyu8266 commentedon Mar 14, 2026
Thank you!
The workaround worked perfectly for me.
The ability to use the terminal on mobile starting from version 1.2.25 is also a huge help for my workflow. 👍
Cellule commentedon Mar 17, 2026
I was able to test the fix using content overrides in the devtools.
I'll open a PR soon
crd2333 commentedon Mar 27, 2026
same problem, and not fixed yet in v1.3.3. Hope for quick merge
waitle commentedon Mar 30, 2026
Still not fixed in v1.3.7.
This is very critical in web based usage...
Infinite http auth request makes impossible to use webUI.
hadestructhor commentedon Mar 31, 2026
Any idea when this will be fixed ? I really love opencode, and I was thinking I could use the web served version on my vps just like how @adamdotdevin said in a podcast I watched the other day.
crd2333 commentedon Apr 1, 2026
A temporary solution before this is fixed (at least works for me), is that set the user_name as
opencodebut set the password personal. And when you use the web app, never touch theterminalbutton (try any other terminals instead, like ssh).hadestructhor commentedon Apr 1, 2026
This is what I'm doing currently, with termux, but I'd like to only use one app instead of switching back and forth. Other than that, what an amazing app opencode is
richard-fairthorne commentedon Apr 4, 2026
I experience this problem in 1.3.12 on Linux under different circumstances, which may help narrow down the cause.
I do not have authentication configured for opencode. Instead, my opencode instance is behind an NGINX proxy which has authentication. Opening the terminal results in an authentication loop.
adrianord commentedon Apr 11, 2026
On OpenCode version 1.4.3, this appears to be fixed. I can have the terminal open without being in an infinite auth loop
Cellule commentedon Apr 11, 2026
Fixed by #19923
thejacer commentedon Apr 27, 2026
This just happened to me. Was running 1.2.x and accidentally clicked terminal, got infinite auth loop. I tried terminating opencode on the server and when it came back up it was still looping. Then upgraded to 1.14.28, still looping. Tried starting it with no password, still looping.
github-actions commentedon Jul 3, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.