OwinResponse cookies not set when remove an HttpResponse cookie
Steve Moss
This is a bug I encountered when working on a web application.
Symptoms
You set a cookie in your OWIN middleware, but the cookie is not returned in the response received by a browser.
The problem may be intermittent.
Common Scenario
You are using an ASP.NET WebForms application with Session
.
You add CookieAuthenticationMiddleware
in the OWIN pipeline.
A user tries to login, seems to do so successfully, but the authentication cookie (with default name .ASPNet.Cookies
) is not set, so the user is redirected back to the login page.
Cause
The problem is described in this Katana Project post:
In OWIN, the response headers collection is the primary storage location for response cookies. System.Web however stores response cookies in a separate HttpContext.Response.Cookies collection and then writes them out to the Response.Headers collection just before sending the response. This can cause a conflict if OWIN if both approaches are used on the same request, as the Response.Cookies collection will overwrite any cookies set via the OWIN response headers.
For the specific example of working with Session, the Session cookie can be removed during the login process. If this happens on the same request as the authentication cookie is being set in OWIN, the authentication cookie will be missing.
How to Reproduce
The problem only seems to happen when httpResponse.Cookies.Remove
is called, as in the following example:
private void SetCookies()
{
var owinContext = HttpContext.GetOwinContext();
var owinResponse = owinContext.Response;
owinResponse.Cookies.Append("owinResponseCookie1", "value1");
var httpResponse = HttpContext.Response;
httpResponse.Cookies.Remove("httpResponseCookie1");
}
If you call this SetCookies
method from a MVC Controller method, “owinResponseCookie1” will not be set.
Note: If you are just adding a cookie using httpResponse.Cookies.Add
, without calling Remove
, this does not seem to cause any problems.
Workarounds
1. Use OnSendingHeaders
If you have control of the code setting the cookies in the OWIN middleware, using OnSendingHeaders
seems to work.
So in the example below, “owinResponseCookie2” should be set, even though “owinResponseCookie1” is missing.
private void SetCookies()
{
var owinContext = HttpContext.GetOwinContext();
var owinResponse = owinContext.Response;
owinResponse.Cookies.Append("owinResponseCookie1", "value1");
owinResponse.OnSendingHeaders(state =>
{
owinResponse.Cookies.Append("owinResponseCookie2", "value2");
},
null);
var httpResponse = HttpContext.Response;
httpResponse.Cookies.Remove("httpResponseCookie1");
}
2. Use only HttpResponse.Cookies OR OwinResponse.Cookies
As there is a conflict, the most robust solution is to only set cookies in one place or the other.
If you are using the CookieAuthenticationMiddleware
then you can override the CookieManager with an adapter that writes the cookies to HttpResponse
instead of using OwinResponse
.
The Katana Project post on this problem gives the source code for a SystemWebCookieManager
to do this. The manager can be plumbed in as:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieManager = new SystemWebCookieManager(),
Fix
This problem should be fixed in the next version of Katana targeting ASP.NET Core 1.0 where:
the storage of response cookies has been standardized to always store them in the response header collection.
Comments
Comments are closed