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
Comments
Anonymous
August 17, 2010
Excellent explanation of the problem and resolution. Wish every article was as clear and concise! Thanks for putting this article together!Anonymous
August 19, 2010
Hey Todd, Very nice to have such feeback from readers. If you have any suggestions on ASP.net topics you would like to see, please do not hesiate to let me know. PaulAnonymous
November 16, 2010
Hi, Thanks for the nice article. Neatly explained. I have a couple of questions -
- FAT is created by server and assigned to the Response object by server which is then placed on the client's system as a cookie. This clearly implies that the FAT is created only after the user is authenticated. So why are you referring to the cookie as "authentication cookie"? Is there a difference between the two?
- Should the same mechanism be used for saving user authentication information across machines (load balanced) & domains (separation of layers into different domains) in a web farm? Vidya
Anonymous
December 30, 2010
I am having same issue with FAT. I tested with your example and looks like after several hours the FAT does not work. I see the cookie and the expiration date is created successful. Is this a problem on my side or server side? ThanksAnonymous
January 19, 2011
Remember ME is NOT WORKING in form authenticationAnonymous
August 17, 2011
This example works in that it sets the cookie and expiration but that's it. The login does not remember the user. Is there another setting in the webconfig? or somewhere else that allows this functionality?Anonymous
August 18, 2011
never mind, I'm a moron, my browser was set to delete cookie and history on exiting browswer. So naturally the scenario test would fail.Anonymous
October 30, 2013
The comment has been removedAnonymous
November 20, 2013
This was the last piece of the puzzle for my article on a combined login, password recovery and new user control. www.gsclayton.net/.../Combined%20Login%20Password%20Reset%20And%20Account%20Creation%20Control%20Using%20AJAX%20Accordion Regards,Anonymous
November 25, 2013
Can u show me the Page_Load of the code??Anonymous
November 29, 2013
I have the same code but using MVC and "Remember me" is not working... is any special treatment for MVC?Anonymous
February 27, 2014
It has been 3.5 years and this still helped a lot! Thanks!Anonymous
June 11, 2014
Note that you will still get a Session timeout even if you have Remember Me selected. Remember Me does not mean the system will remember your session for any longer time than normal. It simply means that the system does not ask you for username and password for a longer time. In fact, authentication cookie is stored separately with session cookie. Explanation in detail: believeblog.azurewebsites.net/.../remember-me-cookiesAnonymous
March 24, 2015
The comment has been removedAnonymous
July 26, 2015
Perfect, Excellent and more. Thank you for perfect explanation.Anonymous
June 06, 2016
The comment has been removed- Anonymous
August 25, 2016
This does not look like it has anything to do with cookies or the fact that you are setting a longer expiration date. It is most likely that the backend server that your application tried to connect to did not respond in a timely manner. If you are using ARR or the sort, you can have a look at this blog post to see how to troubleshoot such stuff: http://linqto.me/ArrErrors - Anonymous
January 03, 2017
The comment has been removed
- Anonymous