How To Correctly Delete Your SameSite Cookies In Chrome (80+)

In my last article I explained how the changes in Chrome 80 (February 2020) can break your existing web sites or web applications, because SameSite cookies will be treated differently. In that post I focused on how to correctly set your cookies and how to mitigate incompatibilities between different browsers, as certain Safari versions don't work correctly with the new way that Chrome enforces.

In this article:

sg
Sebastian Gingter is architect consultant and loves to explain things at Thinktecture. He focuses on Generative AI as well as on backends with ASP.NET Core.

Update: If you want all details about what SameSite Cookies actually are and how they really work, I added a detailed post about that, too.

There is, however, an additional problem you can encounter.

Why doesn't Chrome delete my SameSite=None cookies?

In the new specification Google defines that in order to set a Cookie with SameSite=None, you also have to set the Secure flag.

While the current specification for cookies only describes that in order to delete a cookie, you set a new cookie with an expiry date in the past, it does specifically not require the new cookie (that will overwrite the old one) to set all flags like the original cookie.

With the changes that will be shipped in Chrome 80, this will alter this behavior, too: In order to delete a SameSite=None cookie, the replacement cookie with the expiry date in the past also needs to have the Secure flag set. If that is not the case, the cookie won’t be deleted (as in: the replacement cookie won’t be accepted by Chrome).

However, besides that the cookie should be deleted correctly, anyways. So the way to go is to pass CookieOptions that have set Secure to true when deleting the cookie like so:

				
					Response.Cookies.Delete("CookieName", new CookieOptions()
{
   Secure = true,
});
				
			

This will fix the deletion issue for that cookie. But again….

But my session stays active: The session cookie still isn't deleted!

Yes. There is another issue with that: The ASP.NET Core Authentication cookie is handled a bit differently and is managed by a CookieManager. Unfortunately, since the old spec did not require the secure flag, the code of the CookieManager in the .NET Core Framework (and also in .NET Full Framework) simply does not copy it over to the actual Cookies.Delete() call. Bummer.

If you don’t persist and manage your session on the server, and then rely on actually deleting the session cookie, it will simply stay there and your users will stay signed in into your website / application although they explicitly wanted to sign out.

Note: I strongly encourage you to handle your sessions on the server, so even when a session cookie accidentally stays there, the user will still be treated as signed out.

Luckily this issue should be fixed by Microsoft in .NET Core 3.x and .NET Core 2.1 in January 2020.

As this fix will likely ship in January 2020 and by then .NET Core 2.2 will already be beyond its support lifetime, Microsoft decided to not back-port that fix to .NET Core 2.2. And yes, while 2.2 actually is newer than 2.1, the 2.1 version is the one defined as long-term support (LTS) and as such only this version will get these fixes back-ported. In other words, if you are still on 2.2, you probably should update to .NET Core 3 😉.

If you are on .NET Core 2.2 and cant’t yet update to a version that will be supported for longer, or you are on 3.x or 2.1 and need that fix right now, just stay with me.

Correctly delete SameSite=None cookies in unfixed .NET Core versions

First of all, we need to back port the fix into our project. To do that, you grab the already patched ChunkingCookieManager from the ASP.NET Core repository and copy that class into your project.

Then we need to tell ASP.NET Core to use our patched CookieManager instead of the one that does not copy the Secure flag over.

To do this, we need to adjust our application startup. Locate where your authentication options are configured in your ConfigureServices method or nested calls therein.

				
					public void ConfigureServices(IServiceCollection services)
{
   // find this or similar
   services
      .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
      .AddCookie();
}
				
			

After you figured out where your cookie authentication is configured, adjust the code so that its going to use the patched ChunkingCookieManager instead of the default one:

				
					public void ConfigureServices(IServiceCollection services)
{
   // Adjust to this (or similar)
   services
      .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
      .AddCookie(options =>
      {
         // add an instance of the patched manager to the options:
         options.CookieManager = new ChunkingCookieManager();
      });
}
				
			

Voilà: This will copy the secure flag also over to the delete cookie call, and the new Chrome will be persuaded to really delete your session cookie. In the last weeks we successfully implemented that in several IdentityServer projects and could make sure the cookies were really deleted.

Also make sure that your SameSite cookies are correctly set, as explained in my other post about that.

Summary

Chrome will soon (February 2020) change its default behavior of handling cookies. In the future it will require the Secure flag to be set for SameSite=None cookies. This also applies to deleting these cookies.

While setting Secure = true on the CookieOptions is enough for normal cookies, this does not apply to ASP.NET Core Authentication cookies. There is a bug that prevents the secure flag to be copied to the actual cookie deletion call.

This bug should be fixed in January 2020, but only for .NET Core 2.1 LTS and .NET Core 3.x. For .NET Core 2.2 which is out of support or until the fix is released, this article provides a workaround that ensures that the secure flag will be copied and the cookie will still be deleted when Chrome 80 ships.

Free
Newsletter

Current articles, screencasts and interviews by our experts

Don’t miss any content on Angular, .NET Core, Blazor, Azure, and Kubernetes and sign up for our free monthly dev newsletter.

EN Newsletter Anmeldung (#7)
Related Articles
Angular
SL-rund
If you previously wanted to integrate view transitions into your Angular application, this was only possible in a very cumbersome way that needed a lot of detailed knowledge about Angular internals. Now, Angular 17 introduced a feature to integrate the View Transition API with the router. In this two-part series, we will look at how to leverage the feature for route transitions and how we could use it for single-page animations.
15.04.2024
.NET
KP-round
.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.
15.11.2023
.NET
KP-round
Originally introduced in .NET 7, Native AOT can be used with ASP.NET Core in the upcoming .NET 8 release. In this post, we look at the benefits and drawbacks from a general perspective and perform measurements to quantify the improvements on different platforms.
02.11.2023