Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Login fail with SameSite Cookie + iframe (i.e. MS Team Tab) #361

Closed
ylbillyli opened this issue Feb 24, 2020 · 10 comments
Closed

Login fail with SameSite Cookie + iframe (i.e. MS Team Tab) #361

ylbillyli opened this issue Feb 24, 2020 · 10 comments
Assignees
Labels
more info needed This issue is waiting for more information in order to progress

Comments

@ylbillyli
Copy link

ylbillyli commented Feb 24, 2020

Description

Login fail with SameSite Cookie + iframe (i.e. MS Team Tab)
Maybe related to https://auth0.com/docs/sessions/concepts/cookie-attributes#changes-auth0-is-making ?

Reproduction

  1. In Angular 8, setup the auth service and callback route according to https://auth0.com/docs/quickstart/spa/angular2/01-login
  2. Open Chrome version 80.0
  3. Navigate to chrome://flags/#same-site-by-default-cookies, enable this option and click the Relaunch button
  4. Embed your website that uses Auth0 in a tab , I have tested both the following
  5. Try to Login

EXPECT to login successfully
ACTUAL my app says I am logged out

Potential Root Cause

Tracing the code found that the createAuth0Client function uses storage.ts to check for ClientStorage.get('auth0.is.authenticated') and the ClientStorage uses es-cookie library to store this value on successful login.

My Workaround

I have to save this flag to localStorage and then on app start, manually sync this value to es-cookie using sameSite=None and secure flag, i.e.

Cookies.set("auth0.is.authenticated", "true", { expires: 1, sameSite: "none", secure: true });

before calling the createAuth0Client and now it seems to work fine.

The cookie looks like this after my changes
image

@stevehobbsdev stevehobbsdev added the needs investigation An issue that has more questions to answer or otherwise needs work to fully understand the issue label Feb 25, 2020
@stevehobbsdev stevehobbsdev self-assigned this Feb 25, 2020
@stevehobbsdev stevehobbsdev added the bug This points to a verified bug in the code label Feb 25, 2020
@stevehobbsdev
Copy link
Contributor

@ylbillyli Can you confirm that this works expected when the SameSite flags are turned off? Can you also confirm that syncing your cookie without a samesite attribute value breaks your login?

This cookie should not be affected by SameSite because it's being set by the client-side (SameSite only affects those cookies created by the server).

@ylbillyli
Copy link
Author

@stevehobbsdev Yes, I can confirm that it works perfectly with SameSite flags turned off

Sorry about my bad wording, my fix does not actually "sync" the cookie. As you can see form above screenshot, there are two domains, one form MS Teams and one from ngrok to my localhost. This cookie auth0.is.authenticated is always set to true in the ngrok domain after successful login regardless of SameSite flag on or off. My workaround is just to update this cookie with SameSite=None and secure. Therefore I can't fulfill your second question by sync it without the attribute, the cookie was there already. I just update the SameSite flag as a workaround.

One possible reason SameSite flag plays a role here maybe due to how MS Team embed my app and handle the auth flow in an embedded way. MS Team might also handle cookie differently. As you can see two domains in above screenshot, any chance that the cookie under the ngrok domain was being read by MS Team domain onbehave of my app then passed to my app when accessed via the es-cookie library maybe?

Let me surface more info, when my web app is embedded in MS Team and triggering the auth flow via Microsoft Teams JavaScript client SDK. By calling microsoftTeams.getContext() my code detect that I am running in MS Team embeded mode and uses microsoftTeams.authentication.authenticate() to pop up a window to my auth0 login url (even though we uses redirect flow rather than popup window when running as normal website, MS Teams seems to like popup window more... ). FYI, I am not sure how MS Teams handle the pop up window but it looks like that the popup window did share all my Angular 8 app state (i.e. javascript variable values etc). On successful login, following auth0 doco, my code will trigger authComplete$, in which I call microsoftTeams.authentication.notifySuccess() as per step 7 in the doco above, this will close the popup window and callback to my main embedded app, where I then do a window.location reload to refresh the page. With SameSite off, the app restart on reload and the call to createAuth0Client() on startup will check the cookie in line 21 and continue to line 25 to getTokenSilently which setup the app into a logged in state. However, with SameSite off, this cookie cannot be read and therefore the getTokenSilently is skipped and my app says I am not logged in but the fact is that auth0-spa-js has not even checked my login state.

I believe fixing line 21 to use local storage or update ClientStorage to support setting this flag with SameSite=None and secure will resolve this issue. I am however not sure about other side effect in terms of security concern.

@stevehobbsdev
Copy link
Contributor

stevehobbsdev commented Feb 26, 2020

However, with SameSite off, this cookie cannot be read and therefore the getTokenSilently is skipped and my app says I am not logged in but the fact is that auth0-spa-js has not even checked my login state.

In that case, the workaround here might to just call getTokenSilently manually after createAuth0Client - does that work for you? getTokenSilently itself does not take that cookie into account.

Furthermore, in the current beta (@auth0/auth0-spa-js@1.7.0-beta.3) you are able to use local storage. When you do this, the check on that cookie is skipped.

However, there is an issue with that beta at the moment where the bundled package may not work properly. It's something we're actively working on. (<- this was an issue with a test app I was using, not the SDK itself).

Try the above workaround of calling getTokenSilently manually and let us know how you get on.

@stevehobbsdev stevehobbsdev added more info needed This issue is waiting for more information in order to progress and removed bug This points to a verified bug in the code needs investigation An issue that has more questions to answer or otherwise needs work to fully understand the issue labels Feb 27, 2020
@venku
Copy link

venku commented Mar 10, 2020

We are also experiencing a similar issue. Given I am logged in user and if I reload/revisit the app I see blank page for a minute or so with logs showing that SameSite should be none as a warning below and we get 400 response from the authorize endpoint. After a minute it makes a call to get oauth token which succeeds and lets the app through.

A cookie associated with a cross-site resource at http://auth0.com/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

As mentioned in the previous comment, we have updated the react-spa file to look like this at the initialisation step.

const auth0FromHook = await createAuth0Client(initOptions);
const isAuthenticated = await auth0FromHook.isAuthenticated();
if (isAuthenticated) {
  auth0Client.getTokenSilently();
}

On debugging we found that the code fails on createAuth0Client step itself. We are using a react spa, can you please help.

@stevehobbsdev
Copy link
Contributor

@venku It's likely there are two separate issues here:

  1. The samesite warning is more than likely coming from the legacy cookie that we set to support older browsers and is nothing to worry about

  2. It looks like you're hitting the 60 timeout which normally occurs as a result of a configuration problem. This is covered in the FAQ.

Please check out that page and figure out if your configuration is correct and you're no longer having to wait 60 seconds. If that works, and you're able to sign-in silently just fine then 1) is not an issue either.

@ylbillyli Please let me know if you are continuing to have issues after implementing my suggestion, and we can get this issue closed.

@grutt
Copy link

grutt commented Mar 12, 2020

@stevehobbsdev this issue appears to be resolved with @auth0/auth0-spa-js@1.7.0-beta.4 and setting the Auth0ClientOption cacheLocation to 'localstorage'. However, I was under the impression that storing tokens in localstorage exposed higher risk for xss. Is this addressed in the beta release or am I mistaken?

@stevehobbsdev
Copy link
Contributor

@grutt This is something we're adding as an option for developers that they can use provided they understand the risks of doing so, where the default mode of storage will continue to be in-memory. When using local storage, there is indeed a risk of having tokens stolen through a successful XSS attack, but that risk is not entirely mitigated by using the in-memory option either.

When the beta moves into the stable branch, we will have guidance available that will help you to make a decision about which mode of storage to use in order to meet your own needs, whilst keeping you informed of the security challenges around your choice.

@stevehobbsdev
Copy link
Contributor

@ylbillyli Closing this for now - if you have anything further you'd like us to investigate here, please feel free to continue.

@grutt
Copy link

grutt commented Mar 17, 2020

@stevehobbsdev right, I see. I was more comfortable with in-memory when assessing Auth0 as a vendor.

In this case, I'm not entirely happy with the dump into localstorage as a solution. I appeared to be calling getTokenSilently manually after createAuth0Client and still had this issue. Maybe we can add an option to not perform this check or to selectively store auth0.is.authenticated in localstorage? This issue will probably affect anyone developing ms/chrome addins

@stevehobbsdev
Copy link
Contributor

@grutt Regarding your concerns over in-memory vs. local storage, it's entirely optional and you must opt-in to using local storage in accordance with your requirements.

Maybe we can add an option to not perform this check or to selectively store auth0.is.authenticated in localstorage?

We have just merged into master the ability to access the Auth0Client constructor rather than use the factory function createAuth0Client, which is what performs all those checks. Would this help in your case? You would then have to call getTokenSilently manually to refresh your session but it frees you from having to deal with that cookie.

It hasn't made its way into the beta yet, but I expect that to happen this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
more info needed This issue is waiting for more information in order to progress
Projects
None yet
Development

No branches or pull requests

4 participants