Persisting sessions with React Native

Shrey Gupta
Affinity
Published in
3 min readMar 26, 2018

--

A few weeks ago, we ran into a particularly tricky bug: some users told us that our mobile app was logging them out every time they closed the app. This blog post explains the underlying issue as well as how we resolved it. If you’re running into issues managing sessions reliably with React Native, we hope this helps!

The bug: unreliable cookie storage

After extensive debugging, we found that the mobile app was sometimes sending an invalid cookie to the server when it was re-opened, thus causing the logout issue.

We couldn’t figure out why the invalid cookies were getting sent until we stumbled across the core issue: the cookie storage provided to React Native by the underlying native frameworks isn’t 100% reliable.

Background on cookie management in React Native

(If you’d rather just read about our fix, skip to the next section.)

fetch on React Native is implemented on top of the native networking stacks (Objective-C on iOS, and Java on Android). Cookies are automatically managed by these native stacks rather than by React Native itself [GitHub][StackOverflow].

React Native takes advantage of native functionality on iOS and Android

We found two possible causes of our bug:

Possible cause #1: Native APIs storing the incorrect cookie

We took a look at Apple and Google’s cookie acceptance documentation for their native networking stacks:

iOS (NSURLConnection):

The URL loading system automatically sends any stored cookies appropriate for an NSURLRequest object unless the request specifies not to send cookies. Likewise, cookies returned in an NSURLResponse object are accepted in accordance with the current cookie acceptance policy.

Android (CookieManager):

Cookies are manipulated according to RFC2109.

Since React Native is implemented on top of these APIs, it’s possible that even a cookie manually specified on the application layer can be modified by the native API and replaced with the cookie stored in the native cookie storage (cookies on iOS, CookieStore on Android).

Because cookies are handled transparently, debugging this hypothesis further would have required writing native code, which we decided to avoid for now.

Possible cause #2: Cookies aren’t persisted properly

By default, for performance reasons, cookies are first stored in RAM and then eventually synced to persistent storage (by CookieSyncManager on Android and NSHTTPCookieStorage on iOS).

It’s possible that the cookie never ends up making it to persistent storage (e.g. if the app is closed soon after being opened) — on both iOS [StackOverflow] and Android [StackOverflow].

The StackOverflow recommendation for Android involves forcing a cookie re-sync; for iOS, it involves extending the native API to manage cookies manually.

We still weren’t certain about the particular conditions that might cause cookie persistence to fail, but at this point it looked like building a workaround might be faster than working on fixes at the native layer.

Our solution: manual cookie management

Since we couldn’t rely on default functionality to implement reliable cookie storage, we decided to take matters into our own hands and manage session cookies ourselves.

We chose to use AsyncStorage to store our cookie and set that cookie in the http header in each request. This way, we can ensure that the correct cookie is persisted even if the app is closed or updated. We also use a third party library called react-native-cookies to flush the cookies that are stored by the native cookie managers before each request so that the correct cookie (the one we retrieve ourselves from AsyncStorage) is sent with the request. Here’s a snippet of our code to demonstrate how this process works:

With this change, we’ve resolved the issue, and our users can now stay happily logged in to our mobile app (on iOS and Android). If you’re running into similar issues, we hope you find this useful!

--

--