Remember me checkbox does not work with Forms Authentication

Over the summer, I have been working on developing various ASP.net websites for either Microsoft or personal initiatives (like www.linqto.me). While writing the code for these sites, I decided to implement ASP.net Forms Authentication on each of these applications. When writing the logon screen, I made use of the classic Login control provided as part of the standard ASP.net controls.

Everything works almost out of the box with Forms Authentication, except one small, but, in some cases, significant detail: clicking the Remember Me Next Time checkbox on the Login control will not allow the application to remember the authenticated user the next time around, if in between two attempts to access the application, the user has closed his browser.

Here is the problem statement:

You build an ASP.net Web Application that uses Forms Authentication, and you use a Login control to authenticate users. If the user clicks the Remember Me Next Time checkbox, he or she will still be prompted to re-authenticate the next time he or she comes on to your site if: the user has closed the browser from the last time he has authenticated.

So why doesn’t Forms Authentication Remember Authenticated Users?

The answer is: Forms Authentication Does Remember authenticated users. However the mechanisms by which the authentication ticket is sent to the end user’s browser make for the ticket to be ‘lost’ well before it will ever expire. Let’s look into the details of how this is supposed to work:

Functional Details:

When an end user authenticates on your website using forms authentication, a Forms Authentication Ticket – or FAT is created by the server and encrypted, than placed inside a cookie that is called “ASPXFORMSAUTH”. (The cookie name is actually taken from the “name” element of the Forms Authentication tag inside the web-application’s web.config file – “ASPXFORMSAUTH” is just the default name if you do not change it). The FAT actually has an expiration date, which if the user does not click on Remember Me Next Time checkbox is 30 minutes by default. This value is much higher if the user does select the Remember Me Next Time checkbox.

However (here comes the most important part): the cookie that contains the encrypted ticket also has an expiration date – by default this is at the end of the browser session – when the user closes the browser down completely (all tabs) and opens a new one. This means that the next time the user comes to your site the browser will no longer send back the authentication cookie containing the FAT to the web-application, since the cookie (and not the FAT) has expired. Hence the user is prompted to logon again (see diagram below).

How to keep the cookie from expiring?

The answer to this question is that you cannot keep the auto-generated Forms Authentication cookie from expiring, but you can do the next thing: remove the auto-generated cookie containing the FAT and generate your own. If you chose this approach, you will be deciding for how long the web-application should ‘remember’ the user when he or she clicks on the Remember Me Next Time checkbox when authenticating. You can then place the expiration values on both the Forms Authentication Ticket, and the cookie that will contain the encrypted FAT, ensuring that the cookie does not expire before the FAT does.

This way, the next time the user comes back on your website, even if he or she has closed the browser down completely, the cookie will not have expired, and will be sent back to the server. The FAT contained inside the cookie will be evaluated and if the expiration date on the ticket is still in the future, the user will be authenticated directly. Note that if the user should choose to flush all cookies from the browser cache, the persistent cookie will be deleted as well, and the user will find himself or herself back at square one.

Implementation Details:

To create the persistent cookie and FAT, you have to add some code to the LoggedIn event of the Login control. This event is fired after a user has successfully authenticated onto your site, and after the Forms Authentication Ticket has already been generated by ASP.net, has already been encrypted and added to the authentication cookie of the Response object.

So the first thing needed is to clean Response object. If you have cookies in the Response object that you would like to keep, the safest thing to do is just to remove the Authentication Cookie. In the code sample, I just remove all cookies in that were positioned Response.

       //treat the case where we set the remember me check box
        if (lgvLogin.RememberMeSet)
        {
            //clear any other tickets that are already in the response
Response.Cookies.Clear();

            ......

        }

Following this, a new FormsAuthenticationTicket – or FAT is created – note that issue date is set to the creation date of the ticket, while the expiration date is set to 30 days from the creation date. I am also indicating that the ticket be persistent, so that the user can still send the same ticket even after his current user session has timed out on the server, by passing true for the last but one argument.

         //set the new expiry date - to thirty days from now
            DateTime expiryDate = DateTime.Now.AddDays(30);

           //create a new forms auth ticket
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2,
lgvLogin.UserName, DateTime.Now, expiryDate, true, String.Empty);

            //encrypt the ticket
string encryptedTicket = FormsAuthentication.Encrypt(ticket);

The only thing that is still left to do is to create the authentication cookie. The cookie name is positioned using the FormsAuthentication.FormsCookieName property, to the default cookie name as default in the web.config file in the <Authentucation> section. Once the cookie is created, I set its expiration date to the same date the FAT expires, so as to be coherent – thus the cookie and the ticket contained within will expire at the same date and time. Finally, the new cookie is added to the Response object:

          //create a new authentication cookie - and set its expiration date
            HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authenticationCookie.Expires = ticket.Expiration;

            //add the cookie to the response.
Response.Cookies.Add(authenticationCookie);

Here is the entire code. Note that my Login Control is called lgvLogin:

   protected void lgvLogin_LoggedIn(object sender, EventArgs e)
    {
        //treat the case where we set the remember me check box
        if (lgvLogin.RememberMeSet)
        {
            //clear any other tickets that are already in the response
Response.Cookies.Clear();

            //set the new expiry date - to thirty days from now
DateTime expiryDate = DateTime.Now.AddDays(30);

           //create a new forms auth ticket
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, lgvLogin.UserName, DateTime.Now, expiryDate, true, String.Empty);

            //encrypt the ticket
string encryptedTicket = FormsAuthentication.Encrypt(ticket);

            //create a new authentication cookie - and set its expiration date
            HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authenticationCookie.Expires = ticket.Expiration;

    //add the cookie to the response.
            Response.Cookies.Add(authenticationCookie);
        }
}

And this is how to make the Remember Me Next Time checkbox for ASP.net work when using Forms Authentication.

By Paul Cociuba – ASP.net Engineer - Microsoft

Follow what I read via Linqto.me