title: Forms Authentication and authentication cookie not persisting
body: <p>aware that there are a lot of questions relating to Forms Authentication and the persistence of cookies, but having spent most of a day delving around, I'm still having difficulties.</p>
  
  <p><strong>My Problem</strong></p>
  
  <p>I am working on a web app (VS2010 but webapp is f/w 3.5) which restricts access to certain parts of the app to authenticated users (whereas other parts are open).  My problem is that my authentication cookies do not appear to be persisting after I close the browser.  </p>
  
  <p><strong>My Approach</strong></p>
  
  <p>I have written a simple login.aspx page which is configured in web.config as follows:</p>
  
  <pre><code>&lt;authentication mode="Forms"&gt;
  </code></pre>
  
  <p>
   </p>
  
  <p>...and the individual pages' behaviour are declared like so:</p>
  
  <pre><code>&lt;location path="ClientManageAccount.aspx"&gt;
       &lt;system.web&gt;
          &lt;authorization&gt;
             &lt;deny users="?" /&gt;
          &lt;/authorization&gt;
       &lt;/system.web&gt;
  &lt;/location&gt;
  </code></pre>
  
  <p>...which works fine in every respect EXCEPT for these cookie shenanigans...</p>
  
  <p>I create the authentication cookie manually once I have authenticated my user's login &amp; password against the database (which works fine) in the login.aspx page.  If the user selects the 'keep me logged in' checkbox, the cookie is generated using this method: </p>
  
  <pre><code>    private void GenerateAuthenticationCookie(int expiryInMinutes, Guid userGuid)
      {
          DateTime cookieExpiration = DateTime.Now.AddMinutes(expiryInMinutes); // change to months for production
          var authenticationTicket =
              new FormsAuthenticationTicket(
                  2,
                  userGuid.ToString(), 
                  DateTime.Now,
                  cookieExpiration,
                  true, 
                  string.Empty,
                  FormsAuthentication.FormsCookiePath);
  
          // ticket must be encrypted
          string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);
  
          // create cookie to contain encrypted auth ticket
          var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
          authCookie.Expires = authenticationTicket.Expiration;
          authCookie.Path = FormsAuthentication.FormsCookiePath;
  
          // clear out existing cookie for good measure (probably overkill) then add
          HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName); 
          HttpContext.Current.Response.Cookies.Add(authCookie);
      }
  </code></pre>
  
  <p>The objective here is that I store a user Guid in the auth cookie, which I will then use to restore a user object into session (this is also in the login.aspx page, and my thinking is that I'd like to pluck the user guid from the auth cookie that I have created, and use it to stuff the corresponding user record into session and redirect to the requested page):</p>
  
  <pre><code>    protected void Page_Load(object sender, EventArgs e)
      {
          if (!IsPostBack)
          {
              TryAutoLogin();
          }            
      }
  
      private void TryAutoLogin()
      {
          HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
  
          if (cookie != null)
          {
              FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
  
              if (ticket != null)
              {
                  if (ticket.Name.Length &gt; 0)
                  {
                      try
                      {
                          Guid userGuid = new Guid(ticket.Name);
                          KUser user = UserFunctions.GetUserFromUserGuid(userGuid);
  
                          if (user != null) Session["User"] = user;
  
                          FormsAuthentication.RedirectFromLoginPage(userGuid.ToString(), true);
                      }
                      catch (Exception anyException)
                      {
                          // don't do anything for now - do something smart later :-)                        }
                  }
              }
          }
      }
  </code></pre>
  
  <p>Finally, here is the code for the login button on my login.aspx page:</p>
  
  <pre><code>    protected void Submit_OnClick(object sender, EventArgs e)
      {
          long userId = 0;
          UserAuthenticationStatus status;
  
          status = (UserAuthenticationStatus)UserFunctions.UserAuthenticates(EmailAddress.Text, Password.Text, ref userId);
  
          switch (status)
          {
              case UserAuthenticationStatus.Authenticated:
                  //email address and password match, account ok, so log this user in
                  KUser user = UserFunctions.GetUser(userId);
                  Session["User"] = user;
  
                  if (ChkRememberMe.Checked)
                  {
                      GenerateAuthenticationCookie(15, user.UserGuid); // 15 minutes
  
                      FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), true);
                  }
                  else
                  {
                      FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), false);
                  }
                  break;
              case UserAuthenticationStatus.AuthButLocked:
                  // email/pwd match but account is locked so do something
                  ShowLockedAccountMessage();
                  break;
              case UserAuthenticationStatus.EmailFoundIncorrectPassword:
              case UserAuthenticationStatus.EmailNotFound:
              case UserAuthenticationStatus.Unknown:
                  // either the email wasn't found, or the password was incorrect or there was some other problem
                  // present message stating this and offer chance to register
                  ShowFailedLoginMessage();
                  break;
              default:
                  ShowUnavailableMessage();
                  break;
          }
      }
  </code></pre>
  
  <p>As you can see, there's nothing particularly complex going on, but despite the fact that the authCookie which is created in GenerateAuthenticationCookie(..) being created correctly (as far as I can tell) it does not persist.</p>
  
  <p>One thing I have noticed is that if I place some code into the Application_AuthenticateRequest method in global.asax.cs, such as:</p>
  
  <pre><code>    protected void Application_AuthenticateRequest(object sender, EventArgs e)
      {
          HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
  
          if (cookie != null)
          {
              int x = 4;  // just a dummy line so that I can set a breakpoint
          }
      }
  </code></pre>
  
  <p>...that breakpoint is sometimes hit following a new browser session, although it stops being hit once I navigate away from the startup page (in this case a dummy start.aspx page used purely for dev &amp; testing).</p>
  
  <p>So, apologies for the <em>long</em> question, but I'm truly suffering here.</p>
  
  <p><strong>Things I have checked/tried</strong></p>
  
  <p>Ensuring that the code is being executed - YES
  Browser settings - i.e. no deletion of cookies on exit - CONFIRMED NO DELETION
  Trying different timeouts - e.g. equal or different to the web.config timeout, doesn't seem to matter...
  ...and of course at least twenty or thirty different previous questions, but to no avail.</p>
  
  <p><strong>System/Dev Environment</strong></p>
  
  <p>Windows 7 64-bit, VS2010 (but proj is a 3.5), SQL Server 2008 Express.</p>
  
  <p>On my dev server, this problem remains so I'm not sure it's necessarily environmental - that machine is a WS2008R2 box running SQL 2008R2 - and the same problem remains.</p>
  
  <p>Does anyone, anywhere, have any ideas for things I can try here?  I have a hunch I could get this working by intercepting the initial Application_AuthenticateRequest hit in global.asax.cs and stuffing something into session state to mark as 'authenticated' (to avoid an expensive authentication attempt every time that method is called, which turns out to be several times per page.</p>
  
  <p>Thanks in advance,</p>
  
  <p>John</p>