LibreWolf OAuth browser flow fails (for mailnews.oauth.useExternalBrowser=true): initiates and closes socket before sending actual request to redirect target. Also fails for Firefox with network.lna.allow_top_level_navigation=false
Categories
(Thunderbird :: Account Manager, defect, P2)
Tracking
(Not tracked)
People
(Reporter: blacknaughtyreptile, Assigned: jtracey)
References
(Blocks 2 open bugs)
Details
Attachments
(2 files)
User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:153.0) Gecko/20100101 Firefox/153.0
Steps to reproduce:
Thunderbird 153.0 (Arch Linux, distro package). Default system browser:
LibreWolf 153 (Firefox-based). Fresh Thunderbird profile.
- Add a Gmail account (OAuth2, default mailnews.oauth.useExternalBrowser=true).
- Browser opens Google consent page; complete login and click Allow.
- Google redirects to http://localhost:<port>/?state=...&code=...
Actual results:
Browser shows "Unable to connect" for http://localhost:<port>; Thunderbird
simultaneously reports "Authentication failure while connecting to server
imap.gmail.com". Account cannot be added. Reproduces 100% of attempts.
DIAGNOSIS (tcpdump -i lo on the listener port, capture attached, tokens
redacted): at redirect time the browser opens TWO connections back-to-back:
- An empty one: TCP handshake, then immediate FIN, zero payload bytes
(browser-side speculative/spare connection). - ~130 microseconds later, the real one: plain-HTTP GET /?state=...&code=...
(correct per RFC 8252).
Thunderbird's listener processes the empty connection first, apparently
treats EOF-without-request as flow failure, and closes the listen socket:
the kernel ACKs the GET on connection 2, then Thunderbird FINs connection 1
and RSTs connection 2 without ever sending an HTTP response. The auth code
is never read. A subsequent browser retry connection is refused.
Verified NOT the cause:
- Listener binds fine (127.0.0.1, verified via ss) and stays alive for
minutes if the browser is left idle — no premature timeout. - network.http.speculative-parallel-limit=0 in the browser does not
prevent the empty connection. - The GET is plain HTTP even with the browser's HTTPS-Only local-upgrade
enabled — no TLS involvement.
WORKAROUND: mailnews.oauth.useExternalBrowser=false — embedded flow works
immediately.
Expected results:
The loopback listener receives the auth code and the account is added.
The listener should tolerate connections that close without sending a
request (browser preconnects/spare connections are common), continuing to
listen until a valid request arrives or a real timeout expires. As shipped,
any browser that opens a spare connection at redirect time kills the flow
deterministically.
| Assignee | ||
Comment 1•2 months ago
|
||
Thanks for the detailed bug report; this is likely the same bug as bug 2055308 but my diagnosis for that was wrong. The fact LibreWolf is creating this extra TCP connection at all seems like a browser bug to me, since there is no speculative connection requested and they claim to disable them entirely in their features page. Nonetheless, it is probably a good idea to be more flexible in our handling of connections, and hold off on closing the socket until we get an explicit success or failure (or a generous timeout, but that's a separate issue).
(In reply to Justin Tracey [:jtracey] from comment #1)
Thanks for the detailed bug report; this is likely the same bug as bug 2055308 but my diagnosis for that was wrong. The fact LibreWolf is creating this extra TCP connection at all seems like a browser bug to me, since there is no speculative connection requested and they claim to disable them entirely in their features page. Nonetheless, it is probably a good idea to be more flexible in our handling of connections, and hold off on closing the socket until we get an explicit success or failure (or a generous timeout, but that's a separate issue).
This is due to us setting network.lna.allow_top_level_navigation to false by default, which would also produce the same problems on Firefox. Setting it to true fixes this issue.
Updated•2 months ago
|
Updated•1 month ago
|
| Assignee | ||
Updated•1 month ago
|
| Assignee | ||
Comment 3•1 month ago
|
||
This allows multiple connections to establish to the listener for the external
browser flow, without failing (or succeeding) until one of them sends \r\n.
| Assignee | ||
Updated•1 month ago
|
Pushed by toby@thunderbird.net:
https://hg.mozilla.org/comm-central/rev/d3c239304637
Separate stream from socket in OAuth listener. r=mkmelin
Description
•