Asp.Net MVC – Avoid resetting the form authentication cookie timeout for a request

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.

See Also

Advertisement