Repository navigation
withCredentials: false is a no-op on React Native #84
Description
withCredentials: false is a no-op on React Native — cookies are always sent (RN's XHR defaults withCredentials to true)
Summary
EventSource's withCredentials option defaults to false, but passing false (or relying on the default) does not disable credentials. The constructor only assigns the underlying XHR property when the option is truthy:
// src/EventSource.js
this.withCredentials = options.withCredentials || false;
...
if (this.withCredentials) {
this._xhr.withCredentials = true;
}When the option is false, the XHR is left untouched — and React Native's XMLHttpRequest defaults withCredentials to true, the opposite of the WHATWG default:
// react-native/Libraries/Network/XMLHttpRequest.js
withCredentials: boolean = true;So the effective behavior is: cookies from the native jar are always attached, and there is no way to turn them off through this library's API. withCredentials: false silently does nothing.
Impact
Any app that sets auth headers manually (e.g. a Cookie or Authorization header via options.headers) gets the native cookie jar's cookies layered on top:
-
iOS:
RCTNetworkingsets the request'sCookieheader fromNSHTTPCookieStorage(HTTPShouldHandleCookies = withCredentials), then merges supplied headers withaddValue:forHTTPHeaderField:— which comma-joins onto the existing field. A manually-suppliedCookie: session=Xbecomes:Cookie: session=X,session=XThat's malformed per RFC 6265 (cookie pairs must be
;-separated, andCookiemust be a single header); real-world server frameworks (e.g. Spring) fail to parse the value and auth breaks. -
Android:
withCredentialsis forwarded toNetworkingModule, which only detaches the OkHttp cookie jar when it'sfalse(clientBuilder.cookieJar(CookieJar.NO_COOKIES)) — which, per the above, can never happen through this library.
Reproduction
- In a React Native app, have any cookie for your API host in the native jar (e.g. from a prior webview login or a
Set-Cookieon a previous request). - Open an
EventSourceto that host withwithCredentials: false(or omitted) and a manualCookieheader inoptions.headers. - Inspect the outgoing request (proxy/Charles): the jar cookie is present; with a manual
Cookieheader it's comma-folded into one malformed value on iOS.
Expected
withCredentials: false (the documented default) disables credentials, matching the EventSource/XHR spec semantics the option name implies.
Suggested fix
Assign the value through unconditionally, so false reaches the XHR and overrides RN's non-spec default:
- if (this.withCredentials) {
- this._xhr.withCredentials = true;
- }
+ this._xhr.withCredentials = this.withCredentials;This is what we're running in production via patch-package, and it behaves as expected on both platforms (jar detached on Android via CookieJar.NO_COOKIES, HTTPShouldHandleCookies = NO on iOS).
One consideration: apps that unknowingly relied on jar cookies being sent by default would see them stop when they pass withCredentials: false explicitly — but that's the documented meaning of the option. Keeping the default at true on RN (matching RN's XHR) while honoring an explicit false would also work if you prefer strict back-compat:
this.withCredentials = options.withCredentials ?? true; // document RN's actual default
...
this._xhr.withCredentials = this.withCredentials;Environment
- react-native-sse 1.2.1
- react-native 0.86.0 (verified against its
XMLHttpRequest.js/RCTNetworking.mm/NetworkingModule.ktsources; the relevant RN behavior is long-standing) - iOS + Android
Activity