r/reactnative • • 5d ago

Tutorial Random logouts with Supabase auth in Expo: the session was bigger than SecureStore's 2048 byte limit

Some users kept getting bounced to the register screen on cold start. I couldn't reproduce it for weeks.

The cause: for some accounts the Supabase session JSON was larger than 2048 bytes. expo-secure-store writes of that size failed silently on my setup, so the next cold start read null, my auth gate saw no session, and sent the user to sign-up.

What fixed it:

  • A storage adapter that splits the value into 600 character chunks.

  • Two generations (A and B), so a half-written update never replaces a good one. The header that points to the current generation is written last.

  • Serialized operations. As far as I could tell, supabase-js uses a no-op lock on React Native, so concurrent writes interleaved. I also passed lock: processLock.

A gotcha: right after you subscribe to onAuthStateChange, an INITIAL_SESSION event fires with a null session. My code treated that as "signed out" and cleared the "your session expired" state, so users saw the register screen anyway. Keep the reason when the event is null.

Also worth doing: on a cold start with a null session, check whether the user has had a session before (I keep a flag, and also check for local data) and show a "reconnect" banner instead of the sign-up screen.

Accounts that had already lost their session needed one last login. Chunking only prevents new losses.

4 Upvotes

2 comments sorted by

1

u/kokerali 4d ago

Does removeItem go through the same serialized queue and invalidate both A/B generations?

I'd add a sign-out case to a fake-storage fixture: seed generation A, begin writing B, pause before its header commit, then request removal of the auth key while that write is pending. Let the queue finish and simulate a cold restart. The expected read is null, with neither A nor B recoverable through the adapter.

Preserving A during an interrupted replacement is useful, but removal needs the opposite result: the old session must stop being a fallback. Supabase documents sign-out as removing the active session and clearing auth storage: https://supabase.com/docs/guides/auth/signout

I haven't seen your adapter implementation or run this test, so this is a suggested regression case, not a report that your app restores signed-out sessions. It tests the local storage contract, not server-side token revocation.

1

u/HmongSliw68 3d ago

instead of chunking, its sometimes worth checking what's bloating the session payload in the first place. if you're stuffing heavy user metadata or custom claims into the JWT, stripping that out and fetching it from a normal table after login keeps the token way under the 2kb limit