allBlogsList

Sitecore Authentication and Sliding Cookie Expiration

For security reasons, many sites implement an authentication time limit after a certain period of inactivity. Being a .net application Sitecore could use forms authentication provider to authenticate and validate a user session and by simply specifying values for Timeout and SlidingExpiration in the web.config we should be able to implement this feature.

   <authentication mode="Forms">
      <forms name=".ASPXAUTH" cookieless="UseCookies" timeout="30" path="/" slidingExpiration="true" />
    </authentication>

User session will time out after 30 minutes of inactivity, but if the user interacts with the website at the 29th minute a new cookie that would extend the session validity by 30 minutes is issued. Unfortunately, Sitecore does not recognize the slidingExpiration value and the cookie times out after 30 minutes forcing the user to re-authenticate. This is not ideal and leads to user frustration. Luckily Sitecore is extensible and this issue can be addressed fairly easily by adding a new HTTP module as follows

  1. Create a new class “AuthenticationCookieExpirationModule” that inherits System.Web.IHttpModule
  2. Add a new BeginRequest event to the HttpApplication context
  3. Ensure that the current request is not Ajax (we only want to extend cookie expiration for post back events as a page might have Ajax calls triggered at predefined intervals)
  4. Use FormsAuthentication.RenewTicketIfOld method to get a new ticket.
  5. Update the authentication cookie expiration with the new values and add it to the response object. Note: To prevent compromised performance, and to avoid multiple browser warnings for users that have cookie warnings turned on, the cookie should be updated when more than half the specified time has elapsed.
  6. Finally add the http module to web.config
<system.webServer>
    <modules>
      <add name="AuthenticationCookieExpirationModule" type="Sitecore.Extensions.Handlers.AuthenticationCookieExpirationModule, Sitecore.Extensions"/>
    </modules></system.webServer>

Here is a working example code

public class AuthenticationCookieExpirationModule : IHttpModule

        public void Init(HttpApplication context)
        {
            context.BeginRequest += Context_BeginRequest;
        }

        private void Context_BeginRequest(object sender, EventArgs e)
        {
            try
            {
                HttpApplication application = sender as HttpApplication;
                if (application == null)
                    return;
                HttpContext context = application.Context;
                if (context == null)
                    return;
                if (IsAjaxRequest(context))
                    return;
                if (FormsAuthentication.SlidingExpiration)
                {
                    HttpCookie authCookie = context.Request.Cookies[FormsAuthentication.FormsCookieName];
                    if (authCookie == null)
                        return;
                    FormsAuthenticationTicket currentFormsAutenticationTicket = FormsAuthentication.Decrypt(authCookie.Value);
                    if (currentFormsAutenticationTicket == null)
                        return;
                    FormsAuthenticationTicket newTicket = FormsAuthentication.RenewTicketIfOld(currentFormsAutenticationTicket);
                    if (newTicket != null && newTicket.Expiration > currentFormsAutenticationTicket.Expiration)
                    {
                        authCookie.Expires = newTicket.Expiration;
                        authCookie.Domain = FormsAuthentication.CookieDomain;
                        authCookie.Path = FormsAuthentication.FormsCookiePath;
                        authCookie.Value = FormsAuthentication.Encrypt(newTicket);
                        context.Response.SetCookie(authCookie);
                    }
                }

            }
            catch (Exception ex)
            {
                Log.Error("AuthenticationCookieExpirationModule", ex, this);
            }
        }
        private bool IsAjaxRequest(HttpContext context)
        {
            return context.Request.Headers["X-Requested-With"] != null && context.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
        }
        #endregion
}