auth0 / auth0-react

Auth0 SDK for React Single Page Applications (SPA)
MIT License
866 stars 251 forks source link

Automatically Log Out User when Access Token Expired #178

Closed osseonews closed 3 years ago

osseonews commented 3 years ago

When a user successfully logs in and gets an access token, a cookie is created 'auth0.is.authenticated' which is set to "True". However, this cookie is only deleted when a user/browser specifically calls the log out function. But, if the access token expires, before any logout function is called, the user is never actually logged out of the application, as the cookie is 'auth0.is.authenticated' is still there and set to "True". So how do you automatically log out a user from an application when the access token expires, even if the user didn't actually click on some button to call the logout function?

frederikprijck commented 3 years ago

Hi @osseonews,

This comment should clarify things abit https://github.com/auth0/auth0-spa-js/issues/655#issuecomment-735865411

As mentioned in the link above, there is a difference between logging out (from your Identity Provider) and not having an access token (in your Application). When the access token is expired, the user can still be logged in with the identity provider meaning we can still obtain new access tokens (when using silent auth using iframes) so it doesnt make much sense to logout the user when the access token is expired.

osseonews commented 3 years ago

Thanks. I read the docs. But apparently, from what I can tell, you can just create a cookie called 'auth0.is.authenticated` and set it to "True", and then you can log on to any website that uses auth0-react b/c even if the token is expired, as long as auth0.is.authenticated is true in the browser cooke, the app will run silent authentication, create a token, and then the user is logged in. How exactly is this secure? A user can re-authenticate and a get a new access token with nothing but a boolean cookie value and the app calling getTokenSilently() ? In theory, what should happen, and what happens with other Authorization platforms we have used, is that the access token has a certain lifetime, and when it expires, the user is logged out of everything, unless the application uses refresh tokens in some fashion. From what I can tell there is no use for refresh tokens with Auth0-React b/c the access token can be refreshed nearly indefinately, as long as there is a cookie and the app calls gettokensilently.

hheavener-kyd commented 1 year ago

@frederikprijck This seems to have been closed prematurely. Can you speak to @osseonews' last comment? It seems that determining whether or not a user is authenticated is a matter of a very simple cookie value and doesn't have anything to do with whether or not their tokens have expired. Considering this is likely how most people will check to see whether or not a user is authenticated, this seems to be a serious security issue. Can you please explain how we can trust the library to be secure when this cookie value can so easily be manipulated?

Also, I'm seeking an answer to the original question here as well. I have an SPA that I would like to keep shorter sessions on and would like to have the user be prompted to login again every X amount of hours. However, I'm not entirely sure how to accomplish this using this library in combination with the settings in my Auth0 tenant. Can you speak to this?

frederikprijck commented 1 year ago

Thanks for reaching out @hheavener-kyd

To speak to their comments:

But apparently, from what I can tell, you can just create a cookie called 'auth0.is.authenticated` and set it to "True", and then you can log on to any website that uses auth0-react b/c even if the token is expired, as long as auth0.is.authenticated is true in the browser cooke, the app will run silent authentication, create a token, and then the user is logged in. How exactly is this secure? A user can re-authenticate and a get a new access token with nothing but a boolean cookie value and the app calling getTokenSilently() ?

This isn't entirely correct. The only thing this cookie tells us, is that the user has authenticated before, so we will do a silent auth check on page load. This silent auth check still relies on having an existing session with Auth0, which can only be done by using the proper credentials.

This cookie is mostly an optimization, in cases were we don't have a cookie, we assume the user hasnt been on this app before (or logged out), so we will not do a silent auth call on page load, just to save a, potential useless, call.

If you would manually set the cookie, all you are telling our SDK is that it can try and do a silent authentication check on page load. If you then happen to have logged in with Auth0 before, and the session is still active, yes you will be considered logged in. This doesn't mean you can log in with any user on any application just by setting the cookie, you still need to be logged in to a user on the specified Auth0 tenant domain who has access to the application.

If you would not set this cookie, but just call loginWithRedirect, and the user is already logged in as well, you are also not prompted for your credentials, the above isn't different.

From what I can tell there is no use for refresh tokens with Auth0-React b/c the access token can be refreshed nearly indefinately, as long as there is a cookie and the app calls gettokensilently.

As mentioned above, this is only true for the duration of the Auth0 session.

To reply to your comments / questions:

It seems that determining whether or not a user is authenticated is a matter of a very simple cookie value and doesn't have anything to do with whether or not their tokens have expired

This isn't correct. isAuthenticated is based on the existence of an id token. If you would set the cookie manually, but are not logged in to the Auth0 tenant domain (and silent auth will fail), isAuthenticated will not be set to true.

An id token tells us who you are, the access tokens give you access to API's. When using our SDK, you typically have 1 id token, but multiple access tokens. As long as we have an id token, we have a user, and we consider you authenticated. But that might not mean you have a valid access token. Our SDK will raise an error when you use getTokenSilently if that's the case and it can not silently refresh the tokens.

Also, I'm seeking an answer to the original question here as well. I have an SPA that I would like to keep shorter sessions on and would like to have the user be prompted to login again every X amount of hours. However, I'm not entirely sure how to accomplish this using this library in combination with the settings in my Auth0 tenant. Can you speak to this?

Easiest solution here would be to not use refresh tokens. Not sure if you are, just want to mention that using refresh tokens, indicated by offline_access, basically tells Auth0 that you want to disconnect from the Auth0 session and allow exchanging tokens after that session has expired.

When you do not use refresh tokens, calling getTokenSilently() will either pull a token from the internal cache, or try and contact Auth0 using an iframe. If the Auth0 session is still active, it will return a new set of tokens. If not, it will throw a login_required error and log the user out of the SDK.

The complexity with this approach is that it relies on third-party cookies. So you will need to configure Custom Domains on your Auth0 tenant if you wish to use this approach in browsers that block third-party cookies, such as Safari and Chrome Incognito.

Having said that, you should be able to also use refresh tokens and configure the absolute liftetime, see https://auth0.com/docs/secure/tokens/refresh-tokens/configure-refresh-token-expiration