<< 28,273 days and 19 hours remaining... | Home | Resharper 4 EAP in 2 Weeks! >>

Cookies + Redirects == Nightmares

posted @ Friday, January 25, 2008 12:53 PM

I just wasted probably 8 hours fiddling with cookies in a Monorail app.  The troublesome cookie was the AuthCookie set when using FormsAuthentication

The primary fault was of course my own, in that I was trying to take control of the Authetication process, but still use some of the built-in FormsAuthentication stuff rather than re-write everything from scratch.  Without boring you with details (and after staring at it for 8 hours, I'm likely to misconstrue facts/timeline), I'll give you the very shortened story of my trials.  There were 2 main issues.  The first - most of the time, the logout button didn't log you out.  The second, sometimes the site seemed to not recognized an authenticated user, and push them back to the login screen, which would recognize them as authenticated (so you'd see a login form, and a nice "logout" button in the header).

I started with logout not working.  Seemed simple enough -  the cookie must not be getting killed appropriately.  After some Fiddlering (I want to have Fiddler's children!), I realized that in some circumstances the auth cookie was being set with my local application path, "/MyVirtualDirectory", and sometimes with no path, "/".  This actually creates 2 cookies, and the logout was only killing one of them.  The real story is a little trickier in that I was initially trying to check for the existence of the AuthCookie in the Response, and if it was there, expire it.  Checking for a cookie in the response, effectively creates an empty cookie with that name.  Nice.  But this was my own fault because I wasn't remembering that the Response only has cookies in it if you are setting a new cookie, as opposed to the Request, which carries all the cookies for that path every time (or so you'd think, see below).  So, I cleaned up my mess, made sure only one cookie was set, and only one cookie was killed, on logout.  Now, all my cookie usage was nice and clean, and every cookie was being set with the current ApplicationPath (HttpContext.Request.ApplicationPath or "/MyVirtualDir") which should keep things nice and clean right?

Then I moved on to the random authentication failures.  I quickly found out they weren't random (there is some programming addage about nothing being impossible, or truly random, you just haven't looked hard enough).  What was happening was that on POST requests that returned a 302 redirect response, the browser was not including the AuthCookie in the redirected request.  Like so:

POST:  /profile/create - includes AuthCookie
RESPONSE:  302 Redirect to /profile/index
GET
: /profile/index - no AuthCookie!
RESPONSE: 302 Redirect to login page because authentication fails

WHY ?  WHY ME, WHY?!  WHY?!!?  Why wasn't the browser sending the cookie on the redirect?   Well, dear reader, maybe YOU knew this, but I sure didn't... browser's don't send cookies on redirects UNLESS the redirect response itself set the cookie.  I'm sure there is some reason for this, but I don't get it.

So, how was I supposed to send the cookie again, only on redirects?  I didn't know.  So I decided I'd re-set the cookie on every request, which would have the added benefit of letting me use sliding expiration on the cookie, because I could update the expiration time on every request.  I did so. 

SAME PROBLEM.  I saw the cookie getting set in my 302 response, but the subsequent request was NOT passing it along.  WTF!!??!?  I am sparing you a lot of my trial and error, but what I discovered was that the redirected request would only include the cookie if I set the path to the domain root ("/"). 

So, I had to make sure all my cookie setting code (which was very nicely factored into an HttpHelper class, thank you) set the cookie paths to the root path, and EVERYTHING WORKED. 

Cookies are complicated mofos.  They seem so simple (it's just some strings, right!!!?!), but they can bite you badly.  I still don't understand the rules around when browsers do and don't pass along cookies in redirect scenarios, and I wasn't able to find any specs/standards/rules about it.  All I know is I got it to work and I'm happy for now.


Comments

  1. Pablo

    Posted on: 2/16/2009 5:11 PM

    # re: Cookies + Redirects == Nightmares

    Wow...

    I am writing an application and running into the same errors! I'm so glad I found this blog.. I'm basically repeating what you've done. I've used Fiddler but still to no avail.

    My original request is a "POST /Default.aspx HTTP/1.1" to which the server responds with:

    HTTP/1.1 302 Found
    Connection: Keep-Alive
    Proxy-Connection: Keep-Alive
    Content-Length: 143
    Date: Mon, 16 Feb 2009 21:56:53 GMT
    Location: /Applications/Default.aspx
    Content-Type: text/html; charset=utf-8
    Server: Microsoft-IIS/6.0
    X-AspNet-Version: 2.0.50727
    Set-Cookie: ASP.NET_SessionId=ahsddgqcrjbxus45b1vro0b4; path=/; HttpOnly
    Cache-Control: private

    <html><head><title>Object moved</title></head><body>
    <h2>Object moved to here.</h2>
    </body></html>

    Notice the cookie is set... and to the root path- yet when the browser requests the next page:

    GET /Applications/Default.aspx HTTP/1.1
    Accept-Language: en-us
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
    Connection: Keep-Alive
    Pragma: no-cache


    It doesn't send the cookie back! Also it seems to only work sometimes. What the heck?

    It's very frustrating! Any ideas?

  2. Brian Donahue

    Posted on: 2/20/2009 12:54 PM

    # re: Cookies + Redirects == Nightmares

    Hi Pablo,

    It's been a while, and I can't see offhand why your example isn't working.

    Have you tried setting the domain of the cookie? Does this happen in all browsers? (you can use Firebug on Firefox to see similar info).

  3. Pablo

    Posted on: 2/21/2009 6:02 PM

    # re: Cookies + Redirects == Nightmares

    Hello Brian,

    Thanks for your response!

    I did try setting the domain- among many things. I settled for the default which was already "/".

    Also, I was only able to get it to work once more before and haven't been able to get it working since then.

    My guess was when it did work I had signed in previously into my website while testing, this allowed the cookie to be sent back and so that is when it "worked".

    I'm not completely sure what caused the problem or why, and I only know partly the conditions in which is happens. I will be trying out some tests because I want a definite answer as to why exactly this happens.

    I did come up with a solution (and also quoted your article) here:

    http://jhottengineering.blogspot.com/2009/02/ie-post-and-redirect-errors.html

    Right now, I'm kind of in the same boat with you as far as your last paragraph in this blog post- but I will let you know what I find out!

  4. Paul Elia

    Posted on: 3/16/2009 11:17 AM

    # re: Cookies + Redirects == Nightmares

    The HTTP 1.0 standard per http://www.w3.org/Protocols/rfc2109/rfc2109 in section "4.3.5 Sending Cookies in Unverifiable Transactions" says that cookies should not be set from unverifiable transactions. It states specifically that "Unverifiable transactions typically arise when a user agent automatically requests inlined or embedded entities or when it resolves redirection (3xx) responses from an origin server." So, "Set-Cookie" is not to be acted upon by browsers / user agents for 3xx redirects. Nothing in HTTP 1.1 changes this part of HTTP.

  5. Brian Donahue

    Posted on: 3/16/2009 11:22 AM

    # re: Cookies + Redirects == Nightmares

    Hi Paul,

    I figured there had to be some obscure logic behind this - thanks for the pointer! I wonder, then, what a standards-compliant means for cookie-based authentication would be. Typically, I've seen the login, set cookie, and redirect approach.

  6. Boating Supplies

    Posted on: 8/20/2010 4:32 PM

    # Boating Supplies

    Hey - nice blog, just looking around some websites, seems a reasonably good platform that you're using. I'm at present using Wordpress for a few of my web sites but looking to change.

  7. all new casinos online

    Posted on: 8/26/2010 4:58 PM

    # re: Cookies + Redirects == Nightmares

    I was at Avanade I even had my business cards printed up with Software Craftsman as my title - to the chagrin of a few folks.It was contrary to the Accenture / Avanade model of throwing a bunch of low priced folks at an "engineering" problems with the idea that each are fungible resources.

Your comment:



 (will not be displayed)


  Please add 2 and 1 and type the answer here: