next-auth: NextAuth should not invalidate the client-side session when the browser is offline

Description 🐜

NextAuth invalidates the client-side session when the browser is offline and the NextAuth client cannot communicate with the NextAuth backend. From an application perspective, the expectation is that the NextAuth library must provide the last-known session state unless session TTL runs out or the NextAuth client receives an authoritative response from the NextAuth backend.

How to reproduce ā˜•ļø

git clone https://github.com/nextauthjs/next-auth.git
cd next-auth 
cp app/.env.local.example app/.env.local 
npm install
npm run dev:setup
npm run dev
  • Open http://localhost:3000/protected in Chrome
  • Sign In with credentials using ā€œpasswordā€ as password
  • Observe that the page says ā€œThis is protected content. You can access this content because you are signed in.ā€
  • Open Chrome dev tools Network tab and select the ā€œOfflineā€ mode
  • Minimize the browser window
  • Restore the browser window
  • Observe that the page says ā€œAccess Denied. You must be signed in to view this pageā€

Screenshots / Logs šŸ“½

Logs in browser console:

react_devtools_backend.js:2560 [next-auth][error][client_fetch_error] 
https://next-auth.js.org/errors#client_fetch_error session TypeError: Failed to fetch

asyncToGenerator.js?1da1:6 Uncaught (in promise) TypeError: Failed to fetch

Environment šŸ–„

  System:
    OS: macOS 11.4
    CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
    Memory: 1.37 GB / 32.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.17.1 - /usr/local/bin/node
    npm: 6.14.13 - ~/Temp/next-auth/node_modules/.bin/npm
  Browsers:
    Chrome: 91.0.4472.106
    Firefox: 89.0
    Safari: 14.1.1

Contributing šŸ™ŒšŸ½

I’m more than happy to author a PR but I’m just not sure about the logic behind https://github.com/nextauthjs/next-auth/blob/5a89ab69d3ceee2f84b683b6fa67455126f80815/src/client/index.js#L106 Is there any specific reason to force clientMaxAge=0 session re-validation on keep-alive timer or visibilitychange events? IMO clientMaxAge=0 session must be presumed valid unless the backend says the session is no longer valid (which would be triggered by ā€˜storage’ event).

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 7
  • Comments: 29 (15 by maintainers)

Most upvoted comments

@jozefhruska, the refetchWhenOffline option does an excellent job at hiding this issue in most cases, but it doesn’t eliminate it since it doesn’t fix the root cause. It just makes this issue less frequent but even more challenging to reproduce and troubleshoot, which is a poor customer experience in my books.

Here is a simple demo illustrating this issue - https://pnlkxs-3000.preview.csb.app (source code)

  1. Open the test page
  2. Click the ā€œSign Inā€ button
  3. Sign in with any username and password
  4. Wait till the countdown timer is about to hit 0
  5. Switch your phone into airplane mode or kill the wi-fi on your laptop (you may need to repeat this step several times to catch the bug)
  6. Observe the session state flipped to ā€œunauthenticatedā€
  7. Bring your device back online
  8. The session state remains ā€œunauthenticatedā€

And here is the same demo with a patched next-auth version that does not exhibit this issue - https://m7219t-3000.preview.csb.app (source code)

I’ve updated my project to next-auth@4.10.3 today, and unfortunately, v4 handles unreliable network conditions even worse than v3. It takes just one /api/auth/session network request to fail, and next-auth flips the session to null and completely stops trying to re-fetch the session (even when refetchInterval is defined).

Here is an updated patch for v4: https://gist.github.com/igordanchenko/e1e40c2da14ccdc2823c7fc31a5b2de2

This patch changes next-auth’s bail-out-on-any-network-error implementation to use-stale-while-revalidate semantics. With this patch, the useSession hook consistently returns the last known session state regardless of network errors (browser offline, flaky network, DNS issue, routing issue, backend temporarily offline, etc.)

Installation:

  1. Download the patch file as ./patches/next-auth+4.10.3.patch (the actual file name will be changing as I keep updating the patch for newly released versions)
  2. Follow the patch-package installation instructions - https://www.npmjs.com/package/patch-package

Patch source code: https://github.com/igordanchenko/next-auth/commit/0918a5fbbfd7e11e9d0996fe49ccf27cd81ab375

Thanks for pointing me to that enhancement. However, the more I think about this, the stronger I feel that current behavior is incorrect. And to be clear, my main concern is with the way NextAuth handles network failures / offline mode and not the ā€˜visibilitychange’ event.

Let’s imagine you have an email client app that uses the following session settings:

clientMaxAge: 120,
keepAlive: 5,

These settings establish the following contract: a) let’s use session data on the client for up to 120 minutes before considering it stale b) and also let’s ping the server every 5 minutes to renew the session and reset the 120-minute rolling window

But what is happening is that NextAuth evicts client-side session data even when a single keep-alive call to the server fails and returns no fresh data.

Now imagine you are commuting to work by train reading emails, and all of a sudden, your favorite email app tells you ā€œHey, your session is no longer good, and you need to sign in againā€ all just because the train went through a tunnel and you were offline for couple minutes. This is a bad user experience in my books, and I do not see a clear way for an app developer to work this around unless NextAuth correctly handles failed keep-alive / session refresh calls.

What are your thoughts on this?

Some options to handle offline-ness would be pretty helpful. A few of my users have complained about being sporadically logged out when they are on patchy internet.

I ended up solving this with useSWR https://github.com/nextauthjs/next-auth/issues/596#issuecomment-760251882

Here is code sandbox example using swr and react-query - https://codesandbox.io/s/nextauth-2215-gxoks

With both libraries the app stays mounted and displays previously fetched data.