nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
24.31k stars 3.39k forks source link

Session isn’t being expired correctly (client side) #381

Closed ryanditjia closed 4 years ago

ryanditjia commented 4 years ago

First of all, thank you to all the contributors for this project. Having gone through the course in reactsecurity.io, I think authN and authZ are such complex problems when it comes to decoupled backend and frontend, and not something I’m excited to implement from scratch.

Describe the bug Unless you do a hard reload, the session doesn’t expire correctly client side.

To Reproduce

Or clone the following repo that does exactly the above.

https://github.com/ryanditjia/next-auth-session-expiry-bug

Expected behavior Session should expire correctly on the client-side too.

Screenshots or error logs

image

Additional context

Documentation feedback Documentation refers to searching through online documentation, code comments and issue history. The example project refers to next-auth-example.

iaincollins commented 4 years ago

Thanks for taking the time to submit this.

Client Max Age

You can set clientMaxAge option in the Provider in _app.js to tell the client how often to update the session state.

For example, if you set it to 5 * 60 the client will refresh the client state (at least) every 5 minutes. If your session expiry is longer than this (e.g. 10 minutes) then the client session will not expire, as long as any window or tab for the site in the client remains active.

As long as you set this value to something reasonable (shorter than the session max age), the session will keep rolling as long as they have an active window. If they close a window and re-open it, then the session will be either expired (and they will be signed out in the UI) or else it will be extended (and they will still be signed in in the UI).

If they actively signs out out in a browser, they will be logged out of all windows/tabs.

getSession()

If you want the UI to never be out of sync before rendering, you can use getSession() and make it a blocking call on page render to ensure you check a session before rending a page. Doing this will impact your site performance.

Context / Plans

In future we might change the behaviour of clientMaxAge to make it only revalidate as needed (as version 1 did) which provides some cost/performance savings over fixed poll period. However, how want to handle authentication is always tradeoff, and some people will prefer stale-while-revalidate and some will prefer to use blocking calls.

It's a little easier to understand the impact and tradeoffs when using real world values for settings and how and when this will happen. Typically in popular sites session expiry time is measured in days or months. Some sites like banks use shorter windows (5-15 minutes) but that's at the extreme end of the scale. For context, the default session expiry time is 30 days.

It comes down to can either check session state in a blocking way (and accept the performance and cost impact) or you can accept that sometimes you will render stale data in the UI first. I am sure we will do more enhancements to reduce instances of stale UI state (including updating in the background after initial render) but the current behaviour is as expected.

ryanditjia commented 4 years ago

Thank you for the thorough answer. My example is on the extreme end, and I think it’s a fair tradeoff in a real world setting.

iaincollins commented 4 years ago

@ryanditjia While doing some refactoring for the version 3 beta, I was thinking about your comments.

I've incorporated them into v3 and it includes much more sophisticated behaviour, including new clientMaxAge behaviour, a new keepAlive option and much improved multi-window and event based syncing, that supports very short session expiry times really well.

There is some more info and some detail in https://github.com/iaincollins/next-auth/issues/384

dcorb commented 2 years ago

@iaincollins Is it possible to have a similar behaviour than refetchInterval (replaced clientMaxAge in v4), BUT without extending the expiration? Just to make sure UI can reflect the user is logged out? (Ideally will be synced immediately, when the session token expires)