Repository navigation
Desktop app fails to start after enough launches: authority-bound auth cookies are never purged, and overflow Node's 16 KB maxHeaderSize #11034
nightoperator2000
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Summary
On the desktop app, repeated launches eventually make startup fail every time with:
The cause is not credentials, token state, or network. It is that the browser-session
cookie name is derived from the Host authority, which includes the random listen port,
and issuance never removes sibling cookies. Cookies do not scope by port, so every
historical cookie is sent on the same
Cookierequest header. After enough launches thatheader crosses Node's default
maxHeaderSize = 16384, the Host answers 431, and thedesktop shell reports it as an authentication failure.
Where this lives in the source
packages/client/connection/src/browser-auth.tscookieName(authority) = COOKIE_PREFIX + base64url(sha256(authority))— L116requestAudience()returnsurl.host, so the port is part of the name — L79-88set-cookieand performs no sibling cleanup — L284, L344authenticate()looks the cookie up by name derived from the current authority, thenrequires
payload.authority === authority— L375-380That last point is the important one: a cookie issued for a previous port can never
authenticate again. Those rows are pure dead weight — so deleting them is
behaviour-preserving, not a workaround with side effects.
Measurements
Each cookie is ≈ 228 bytes (name 52 + value 173 + 3 separator bytes).
An injected-cookie sweep against a running Host:
CookieheaderOn the affected machine, real startup broke at 71 accumulated cookies.
Note the discrepancy honestly: the synthetic sweep still answered 303 at 72, while the real
desktop request failed at 71. The synthetic request carries far fewer accompanying headers
than the shell's
net.fetch(UA, Accept, Sec-Fetch-*, …), so the real break point isearlier than the sweep suggests. Treat the sweep as a lower bound, not the threshold.
Why the error message misleads
Two hops use different requests:
authenticateWebHost()— plain Nodefetch,redirect: 'manual', no cookies→ clean 303 +
Set-Cookie→ "authenticated"connectDesktopWelcome()—net.fetch(url, { credentials: 'include' }),sends every accumulated cookie → header too large → 431 → throws
Web authentication failedThe first hop succeeds and the second fails, so the message blames authentication while the
actual condition is HTTP header size. This is worth fixing in the message itself — it sends
readers toward credentials.
Suggested fixes
dsh-auth-*cookies at issuance. Safe by thepayload.authoritycheck above. Caveat: cookie scope ignores port, so if two instances must run
concurrently, purge only siblings whose authority is not currently listening.
A simple total-count cap is an equally acceptable alternative.
maxHeaderSizeonly moves the break point; it does not stop the accumulation.User-facing workaround
Quit the app completely first (a running app rewrites the jar from memory), then:
No re-login is needed — the shell re-issues a cookie from the launch URL on the next start.
Delete only the
dsh-auth-%rows; do not delete the database.Environment
maxHeaderSize = 16384, unmodifiedAll reactions