I have a site that is using Asp.Net’s forms authentication, with sliding expiration. A user may log in and make some operations (requests), and after 30 minutes (for example) from her last action, she will be logged out.
However – what if I want to make a request that will not reset that timeout? For example, I may want to send an Ajax request for tracking the user, periodically check for notices, etc. How can I prevent that “system” request from extending the authentication cookie?
As it turns out, there is a simple way of doing that, once you understand exactly how sliding authentication works in asp.net.
I won’t go into too much detail, but the basic mechanism is:
- After authentication, an authentication cookie is sent to the user, with expiration time of 30 minutes (or whatever you defined).
- The authentication cookie contains an encrypted data, which is really the authentication ticket.
- The ticket contains information related to the authentication, and the expiration time. Note the browsers don’t send the cookies’ expiration times when making a request, so that data is included in the authentication ticket instead.
- For actions the user does in the first half of the expiration period (that is, the first 15 minutes), nothing happens. The authentication timeout does not reset.
- On requests that happen on the second half of the expiration period, the timeout is reset, and the expiration is extended by another 30 minutes.
So, there is a chance our response will contain a new auth cookie, with extended expiration time. If the user is inactive, and our periodical action is the only thing happening, one of the responses will contain a new cookie, and the user will be logged in indefinitely.
So, how an we prevent that? This is as simple as removing the cookie from the response:
///<summary> /// Prevent the auth cookie from being reset for this action, allows you to /// have requests that do not reset the login timeout. /// </summary> public class DoNotResetAuthCookieAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var response = filterContext.HttpContext.Response; response.Cookies.Remove(FormsAuthentication.FormsCookieName); } }
Use of this action is pretty simple:
[DoNotResetAuthCookie] public ActionResult SampleAction() { return Json(new {Request.IsAuthenticated, CookiesCount = Response.Cookies.Count}); }
Notes
- You may also want to disable caching for such an action, using OutputCacheAttribute
[OutputCache(NoStore = true, Duration = 0)]
- I have some more defensive code in production (some more null checks), but this should be ok. Specifically, you don’t have to test the cookie is actually there to delete it: HttpCookieCollection.Remove
- I used this to check if the user is still logged in, and get the time she will (presumably) log out – I needed something that works in an Ajax application, with many possible tabs or windows open.