I have answered over 1000 questions on Stack Overflow, and cookies are a common source of trouble for developers, especially when working with authentication and OpenID Connect in ASP.NET Core.

Debugging cookie problems in ASP.NET Core

Troubleshooting cookie problems in ASP.NET Core

I have answered over 1000 questions on Stack Overflow, and cookies are a common source of trouble for developers, especially when working with authentication and OpenID Connect in ASP.NET Core.  

Cookie problems can, in my experience, be categorized into the following categories:

  • Browser Rejection
    Cookies provided by the server that aren’t accepted by the browser.
  • Browser Omission
    Cookies in the browser are not included in requests to the server.
  • Lost cookies
    Cookies that are lost on the way to the server.

In this blog post, I will detail how you can troubleshoot these categories of problems, look at some ASP.NET Core cookie issues, and more.

 

Cookies rejected by the browser

When setting a cookie, we use the set-cookie response header, often accompanied by the secure and samesite attributes. Below is an example illustrating the setting of five common cookies:

				
					HTTP/1.1 200 OK

Set-Cookie: NormalCookie=NormalValue;Path=/

Set-Cookie: NormalCookieWitSecure=NormalValueSecure;Path=/;secure

Set-Cookie: StrictCookie=StrictValue;Path=/;SameSite=Strict

Set-Cookie: LaxCookie=LaxValue;Path=/;SameSite=Lax

Set-Cookie: NoneCookie=NoneValue;Path=/;SameSite=None;Secure

…
				
			

(Note: This article will not go into the details of the pathdomain, and the HttpOnly attribute. The HttpOnly attribute is all about restricting JavaScript from accessing cookies.). I recommend setting the HttpOnly attribute on every cookie that never needs to be accessed by JavaScript.

How can I tell if the browser accepts a cookie?

The first step in troubleshooting cookie problems is to verify that the browser has accepted the cookie.

To see which cookies it has received and accepted, open the browser developer tools (F12) in Chrome and look under Application -> Storage -> Cookies.

If the expected cookies are not found here, then head over to the Network tab, locate the request that sets the cookie, and then click on the Cookies sub-tab:

 

Rejected cookies are highlighted in yellow. Hovering over the information (i) icon displays reasons for the blockage. As shown in the example below:

You can also activate the “Has blocked cookies” checkbox to only show requests with blocked response cookies.

Some of the most common reasons for blocking are:

  • Using samesite=none without the secure attribute
  • Trying to set a cookie with the secure attribute over HTTP://
  • Too large cookies; keep the cookie size below 4000 bytes for maximum browser compatibility. 

Cookies not included in requests

If you have concluded that the browser has accepted the cookie and it is found under Application -> Storage, great! One step forward! What’s next?

There are a few reasons why the browser might decide not to include cookies in outgoing requests:

Some of the reasons for blocking are:

  • Protocol Mismatch Cookies with the secure attribute will not be included in requests over HTTP.
  • Incorrect samesite For cross-site requests, you must use:

    • samesite=none;secure when you need to support GET & POST in requests to another site

    • samesite=lax when you only need to support GET requests across sites.

  • Cross-Origin Resource Sharing (CORS) We won’t go into CORS in this blog post. CORS can be problematic when you do API requests from JavaScript, using the XMLHttpRequest or Fetch APIs.

Under the network tab, you can see why a cookie was not included in the request, as shown in the example below:

 

Common same site problems

Some of the common samesite problems that I see are:

  • SameSite=none cookies
    Cookies set with the samesite=none attribute must also be marked with the secure attribute. This means that these cookies must always be used over HTTPS.  This is a common problem, for example, when working with OpenID Connect.
  • Missing samesite header?
    All cookies that you set should have a samesite attribute. Otherwise, you might end up with unexpected issues where browsers will start to block them in certain circumstances.

    For example, Firefox writes this warning to the console when you try to set a cookie without a valid samesite attribute:

Cookie “NormalCookie” does not have a proper “SameSite” attribute value. Soon, cookies without the “SameSite” attribute or with an invalid value will be treated as “Lax”. This means that the cookie will no longer be sent in third-party contexts. If your application depends on this cookie being available in such contexts, please add the “SameSite=None“ attribute to it. To know more about the “SameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite 

Which samesite value should you use?

Some guidance about what value to use:

  • Strict
    Use this value for cookies that only should be used within the same site. For example, do consider using this value for your session cookie. Using strict cookies brings the maximum protection against Cross Site Request Forgery (CSRF) attacks.
  • Lax
    This is the new default for cookies, which only includes the cookie GET requests across sites.
  • None
    Use this value for cookies that should be included in all site requests. This value must be set together with the secure attribute. This is the least secure option. This makes the cookie behave like they behaved before the samesite concept was introduced. 

Cookies in ASP.NET Core

What can go wrong when we use cookies in ASP.NET Core?

When you use the cookie authentication handler, the default session cookie is set as follows:

				
					Set-Cookie: .AspNetCore.Cookies=xxxxxxx; path=/; secure; samesite=lax; httponly
				
			

This is a sensible default. You might be tempted to set the session cookie to samesite=strict, as follows:

				
					
builder.Services.AddAuthentication()

                .AddCookie(opt =>

                {

                   opt.Cookie.SameSite = SameSiteMode.Strict;

                });
				
			

If you just use local authentication (like ASP.NET Core Identity), that is usually fine. But, when you use it together with OpenID Connect, you will have problems, as shown in the image below:

OpenID Connect, cookies, and IdentityServer

When you work with OpenID Connect, plenty of cookies will be involved. For example, if you use Duende IdentityServer, then the following cookies are involved during authentication:

Not properly configuring and understanding these cookies is a common source of problems.

Same domain but different ports

You might think that when you have multiple sites on the same domain but on different ports, they would have separate cookie jars:

But it turns out that they will all share the same cookie jar. The cookies are tied to the domain, not the port or scheme.

Summary

I hope the steps outlined above can help you troubleshoot your cookie problems. Here are some tips for healthier and more secure cookies:

  • Always use HTTPS
    Most cookie problems will go away when you move your traffic to HTTPS. Using HTTPS today is also a must If you care about security.
  • Set samesite
    Always add the correct samesite attribute; this is a must today.
  • Add the secure and HttpOny attribute
    Securing our cookies and all sensitive cookies should always have these two attributes set.
  • Do research the path and domain attributes
    They can be used to further restrict to what domain (including sub-domains) and path the cookies should be included on.

Feedback, comments, found any bugs?

Let me know if you have any feedback, anything I missed, or any bugs/typos. You can find my contact details here.

About the author

Hi, I’m Tore! I have been fascinated by computers since I unpacked my first Commodore VIC-20. Today, I enjoy providing freelance development and developer training services, focusing on ASP.NET Core, IdentityServer, OpenID Connect, Architecture, and Web Security. You can connect with me on LinkedIn and Twitter, and you can find out more about me and my services here, as well as my courses for developers, including my course, Introduction to IdentityServer and OpenID-Connect.

Share This Story
Share on linkedin
Share on twitter
Share on facebook
Share on pinterest
Share on email

About me

My name is Tore Nestenius and I’m a trainer and senior software developer focusing on Architecture, Security and Identity, .NET, C#, Backend, and Cloud, among other things.

Do You Want Tore To Be Your Mentor?

Categories