Logout endpoint not invalidating sessions

I have an application using the Auth0Lock for an implicit flow. I have a logout system that uses the Auth0lock to direct the browser to send the logout request to Auth0 to invalidate the auth0 session.

Occasionally during development I’ve seen the logout URL get touched (watching in Chrome networking tab), and getting a 302 response back, but then the user is able to log back in. This doesn’t seem like it should be possible.

Does auth0 guarantee destruction of the session on a 302 response? How long does it take to destroy the session? Is the session destruction a blocking operation that only returns when the session is absolutely gone, or does the session destruction operation return as quickly as it can before the transaction is fully committed?

The only thing I can think is that Auth0 is using some kind of eventually consistent database under the hood (like Riak) and when I logout, and renavigate to the login screen I’m seeing the old session that hasn’t been completely invalidated on the Auth0 side.

Can someone from Auth0 shed some light on this?

1 Like

HI @jazzepi Welcome to Auth0 community.

If you are redirecting user to auth0 /logout endpoint then Auth0 will definitely invalidate user session on auth0 side. However we need to understand which session you are talking about. There can be three sessions as described here Session Layers

A HAR file of network requests would also help to troubleshoot Generate and Analyze HAR Files (Remember to scrub any confidential information such as username/email, owd and client secrets from the HAR file before uploading)

1 Like

I think I found the problem. I believe there is a race condition in the Auth0 code relating to storing a nonce cookie in the domain of the website Auth0 is securing.

Steps to replicate

  1. A user enters credentials and clicks the login button on the Auth0Lock.
  2. Immediately a user receives a nonce cookie on the domain of the website being secured by the Auth0Lock (NOT THE AUTH0 DOMAIN). I believe this happens before the HTTPS request to authenticate has been made to the auth0 domain.
    This cookie begins with the com.auth0.auth. namespace.
  3. The HTTPS request to the auth0 domain “authorize” endpoint succeeds and returns a 302.
  4. The browser loads the new webpage with the url returned in step 3.
  5. When the Auth0Lock is instantiated by Javascript it looks at the URL, cuts out the hash, stores the token, changes the URL to delete the hash, and then deletes the nonce.

Critically, in step 5 before the nonce cookie is deleted I can log myself out of my application. In this logout procedure I call logout() on the Auth0Lock object, delete our copy of the access token credentials being stored in localstorage, and then refresh the browser.

At this point the user should have had both the local application session invalidated (by deleting what was stored in local storage) and the Auth0 session, but they’re still presented with the Last time you logged in with pane. This is the core of my problem. Users should not see that screen, and they should not be able to immediately log back in.

I’m not sure what the logic is inside of the Auth0Lock to decide when to display the “login again”, but if either the auth0.ssodata or com.auth0.auth cookies are deleted the login again screen will not display which is the behavior that I expect.

So I think the fix to this is that Auth0Lock should delete the cookies that it created when .logout() is called on it instead of me having to delete those cookies for it. That way even if I logout before the nonce cookie is deleted, Auth0Lock won’t get confused and present the user with the wrong prompt.

As a work around I’m using this code in my logout method.

const cookies: string[] = document.cookie.split('; ');
      cookies.forEach((cookie: string) => {
        if (cookie.startsWith('auth0.ssodata') || cookie.startsWith('com.auth0.auth')) {
          console.log(`Handling cookie ${cookie}`);
          const d = window.location.hostname.split('.');
          while (d.length > 0) {
            const cookieBase = encodeURIComponent(cookie.split(';')[0].split('=')[0]) + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=' + d.join('.') + ' ;path=';
            const p = location.pathname.split('/');
            console.log(`Clearing potential cookie at ${cookieBase + '/'}`);
            document.cookie = cookieBase + '/';
            while (p.length > 0) {
              console.log(`Clearing potential cookie at ${cookieBase + p.join('/')}`);
              document.cookie = cookieBase + p.join('/');
              p.pop();
            }
            d.shift();
          }
        }
      });

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.