Mvc: Can not retrieve cookie-based TempData after Google authentication with account selection in Google Chrome

Created on 4 Jan 2018  路  11Comments  路  Source: aspnet/Mvc

Using ASP.NET Core 1.1, I set up cookie-based TempData. Within this key/value store, I stored temporary data prior to logging in to an external login provider (Google) which I retrieved in the callback of the authentication request.

This worked and I do not recall any problems with this.

I now upgraded to ASP.NET Core 2.0. One of the changes made is cookie-based TempData is now configured by default (using CookieTempDataProvider if I am not mistaken). Indeed, when removing the configuration the data stored temporarily when logging in with Google Authentication can still be retrieved.

However, I now noticed this fails when multiple Google accounts are configured in Google Chrome and the user needs to make a selection which one to log in with. When only one account is configured no interaction is needed, the user is logged in automatically, and TempData can be retrieved. I am not certain whether or not this problem occurred in ASP.NET 1.0. Possibly I simply did not run into it.

Debugging this, I noticed that the cookie is written (can see it in Chrome settings) and is even still there when the authentication callback is called. Regardless, TempData is empty when queried. An exception occurs since the expected key can't be found, and only subsequently the cookie is no longer visible in Chrome settings. Interestingly, only the TempData cookie is removed. Even more interesting, this problem does not occur on Microsoft Edge!

I also posted this on StackOverflow, but since it seems like a bug I posted it here.

3 - Done bug

All 11 comments

I did some further debugging by duplicating the CookieTempDataProvider and naming it CustomCookieTempDataProvider and registering this one in Startup.cs:

services.AddTransient<ITempDataProvider, CustomCookieTempDataProvider>();

This allowed me to see what happens when/if LoadTempData() and SaveTempData() get called. Both get called as expected, but when SaveTempData() gets called when the authentication callback occurs, the TempData cookie (.AspNetCore.Mvc.CookieTempDataProvider) is not listed, even though it is visible from Google Chrome's cookie details (chrome://settings/cookies/detail).

        public IDictionary<string, object> LoadTempData( HttpContext context )
        {
            if ( context == null )
            {
                throw new ArgumentNullException( nameof( context ) );
            }

            if ( context.Request.Cookies.ContainsKey( _options.Cookie.Name ) )

context.Request.Cookies does not contain the expected key.

It thus seems the problem could lie even lower than the implementation of CookieTempDataProvider.

@Tratcher do you think this could be a browser cookie-size limit?

It may be an issue with the SameSite setting. The auth flow includes a stop at google's login page. When you enter your credentials and continue the new redirect flow now considers google the origin and excludes same site cookies from any subsequent requests. We had to disable SameSite for all of the auth cookies because of this.

@Tratcher That sounds likely. I'll try to change SameSite through CookieTempDataProviderOptions:

SameSite defaults to Strict.

Tonight I will try whether setting this to Lax fixes the issue. Lax seems default for CookieBuilder. Any documentation/clarification on why this is overridden by CookieTempDataProviderOptions?

If this were to work, is there anything I need to watch out for since all TempData cookies will be set to Lax? Again, just wondering about the motivation why it was set to strict without an easy way of changing it on a per-cookie basis.

The reason it might work on Microsoft Edge could be because SameSite does not seem implemented there:

As of November 2017 the SameSite attribute is implemented in Chrome, Firefox, and Opera.

SameSite is a new standard and we're still figuring out all of the ramifications. Temp data is assumed to be for page-to-page operations, I don't know if we anticipated using it to span an auth flow.

To report back on @Tratcher's suspicions, this is definitely related to the SameSite option. Setting SameSite to SameSiteMode.Lax in Startup.ConfigureServices() resolves the reported issue.

// Ensure TempData cookies do not get cleared when passing through external Google Authentication.
services.Configure<CookieTempDataProviderOptions>( options =>
{
    options.Cookie.SameSite = SameSiteMode.Lax; // By default this is set to 'Strict'.
} );

I will leave the issue open as it might still need to be investigated what the desired/expected behavior should be here.

Note with SameSite cookies are not deleted from the client, they are only excluded from requests where the user action originated on some other site. The users next request on your site would include the cookie.

@blowdart @Eilon @danroth27
This becomes a question regarding our defaults and whether using Strict is really the right choice for cookies emitted by the framework that are required to make our features function correctly. Also, whether subsequently changing them is breaking.

My initial thought is the Temp Data cookie shouldn't be strict be default, as it's already protected from tampering and spoofing and thus the making it strict simply results in the feature not working as expected in some cases (like here).

Interested to hear others' thoughts.

Yeah, I'm don't believe that we understood this implication when we made this change.

@DamianEdwards I don't know how authoritative Open Web Application Security Project (OWASP) is, but they seem to imply that SameSite should default to Lax:

The default lax value provides a reasonable balance between security and usability for websites that want to maintain user's logged-in session after the user arrives from an external link. In the above GitHub scenario, the session cookie would be allowed when following a regular link from an external website while blocking it in CSRF-prone request methods (e.g. POST).

This is correctly implemented in CookieBuilder. It is weird CookieTempDataProvider would deviate from this behavior without any motivation why.

Therefore I agree this could be considered a bug.

@kichalla, can you please handle this? Thanks!

Was this page helpful?
0 / 5 - 0 ratings