Sync auth state between multiple applications (SPA & Chrome Extension)

Hello!

I’ve configured auth0-chrome on an extension and auth0-spa-js on a SPA.
Both applications use the same Auth0 tenant, however when a user logs in/out in one application, they don’t automatically get logged in/out the other application. The user has to enter their credentials each time, to login in each application, and logout each time in each application.

I understand that existing access tokens can’t get automatically revoked across applications, but shouldn’t the user be automatically logged in across applications when calling authentication methods like getTokenSilently?

Is this behaviour expected, or is there something misconfigured?
Thanks!

1 Like

Hi @minibar,

Login/logout works on 3 layers. There is the application session (in the case of a SPA this is a token cached in memory), the auth0 session (this is a cookie that is related to the login domain, and allows for things like SSO across applications on a browser, or lets a SPA refresh a token silently in an iframe checking that there is a valid auth0 session), and the idp session (which is maintained by the idp, whether that is a social provider like google/facebook, or an enterprise provider).

Outlined here:

With that in mind, we use the auth0 session to allow a user to login to Application A, starting a session (cookie) with auth0 and the login domain, and when Application B directs a user to login to that domain auth0 will verify the session and return a token without prompting for login.

I am not familiar enough with chrome extensions to give a full blown solution, but it should be possible to log a user into your SPA, start the session with auth0 via the cookie, then have the user login to the extension without having to provide credentials. This assumes the extension has access to the cookie in the browser.

Hope this helps!

Thanks,
Dan

It seems to be currently impossible to benefit from Auth0 SSO authentication state sync using the auth0-chrome SDK, because the chrome.identity.launchWebAuthFlow API which it uses, doesn’t share cookies with the rest of the browser space. It requires the user to enter their credentials again, even if the user has already done so in a different web application using the PKCE auth flow, for the same browser and tenant.

Judging by the other issues this API seems to have – like the lack of an address bar – and the level of inactivity in the bug reports aforementioned, it is unclear if/when these issues will be fixed.

A disclaimer should be added both to the README and to Auth0 docs, explaining this limitation.

I would also be great if Auth0 could recommend a solution.

I’ve managed to use the auth0-spa sdk loginWithPopup() with success. It offers the same experience as the auth-chrome but with none of the drawbacks:

  • It syncs the login state through cookies
  • The popup has a url bar so the user can verify they are introducing the credentials in the right domain

@dan.woda I would look into this and consider deprecating auth0-chrome in favor of the auth0-spa sdk

3 Likes

@minibar what’s your setup on the auth0-spa, particularly on the redirect_uri? i’m trying to achieve the same thing with migrating from auth0-chrome.

@warex03 if with redirect_uri you mean the callback url you can use the origin of the page where the login is initiated i.e chome-extension://92fji2j3f093feereouw. If that page is a chrome extension page, like chrome-extension://92fji2j3f093feereouw/…), you will have to use the loginWithPopup() method, since the normal loginWithRedirect won’t work (at least without some extra work), because Chrome disallows redirects back to chrome-extension:// for security reasons.

@minibar thanks for the quick reply! it seemed to work, at least im not getting an error with the popup now. i tried running it in a background script but i’ll try to figure out how to wire it up with our backend. ideally, we want it to work with google sign in and get the idp access token and also be able to refresh the token silently since it only lasts for 1hr.

hey @minibar - I’m currently trying out the same, but unfortunately, the redirect doesn’t seem to work. I can authenticate succesfully in the PopUp, this is closing the whole extension window. When opening again, I’m not longer authenticated - any ideas?

@jannik I don’t see why the an window window should be closed after you authenticate using loginWithPopup(). What window are you referring to?

Hi, thank you for answering. I could fix the issue myself by using cacheLocation='localstorage'
Otherwise, auth0 just sets the cookie in the open popup, which is not persistent. On closing of the popup I was no longer authenticated.
Like this it’s working :slight_smile:

1 Like

A popup is like any other window and cookies will be persisted as if you were authenticating in a separate tab – assuming you are using auth0-spa-sdk, and not the deprecated auth0-chrome sdk

1 Like

storing credentials in localstorage has security implications

1 Like

I would like to echo the sentiment from @minibar , localstorage can cause some security concerns.

With that said, the new refresh token rotation flow allows for the storage of rotating refresh tokens in localstorage. You can set the storage location in the spa sdk with the cacheLocation options, I am assuming that is what you did here @jannik. If you are conforming to those guidelines you should be good to go.

As far as I understand, refresh tokens in local storage (and its security vulnerabilities) could be avoided if auth0 allowed the inactivity timeout to be increased to more than 3 days:

Is there a reason why auth0 doesn’t allow this setting to be increased in dev plans, and is instead suggesting customers to follow less secure practices?

Thanks

@minibar,

This may be true for the immediate future, but we are likely to see more browsers use features like Safari’s ITP to block third party cookies, and that is why the refresh token rotation flow is being rolled out.

To be clear, rotating refresh tokens are not the same as native app refresh tokens. They are designed with browser applications in mind, and have security mechanisms for that use-case. This blog dives into it.

No one is suggesting you disregard security practices to get around pricing tiers. As I described above, refresh token rotation is taylor-made for SPAs, it is secure, and it just so happens to solve this problem.

As for why there is a difference between dev and enterprise features, that is a question for the sales team. You can start the conversation with them using the ‘talk to sales’ button in nav bar, even if it is just feedback and you aren’t looking to upgrade, they are the best place to send that info.

Thanks @dan.woda for making that clear. And yes, I’m using the cacheLocation option of the SPA sdk to set it to localstore. It wasn’t possible to use just in memory, as described before.
I’m also already testing the new rotating refresh token possibility - good that this feature was just released :wink:

Kind regards,
Jannik

2 Likes

@jannik to be clear, it is currently possible to use the default cacheLocation. localStorage is not required when using loginWithPopop() in Chrome to take advantage of the silent authentication method.

@dan.woda thank you for sharing that blog post and providing additional information about refresh tokens. Refresh tokens stored in local storage seem to present security risks not shared by session cookies, even when “acceptable mitigations” (as stated in the blog post) like refresh token rotation are used. Rotating refresh tokens mitigates some of the security risk, but doesn’t doesn’t eradicate all of it. Would it be fair to say that they are not as secure as session cookies?

As far as I understand the problem with 3rd party cookies can be solved by configuring custom matching domain, right?

To clarify and be fair, I was not referring to something which was suggested in this thread.

1 Like

If you see that kind of content here please flag it or DM me and I will remove it.

thanks for this thread, it has been extremely helpful. I was running into a similar issues as @jannik and the refresh with the cacheLocation was a good way to solve it. But now I’m running into an issue where logout isn’t triggering when I click it and trigger it. Anyone else facing something similar

1 Like