16

I have an asp.net site that I need to have a popup/layer/alert happen when the session reaches its timeout (lets say 10 minutes). The popup will say that your account session will exprire due to inactivity and have a button for continue session or a button for logout.

I see different ways to do this online, but what's the best/proper way to handle this? Do I have to put an additional timeout if the popup is open too long?

cdub
  • 24,555
  • 57
  • 174
  • 303

7 Answers7

27
<script type="text/javascript">
    var sessionTimeoutWarning = "<%= System.Configuration.ConfigurationManager.AppSettings["SessionWarning"].ToString()%>";
        var sessionTimeout = "<%= Session.Timeout %>";

    var sTimeout = parseInt(sessionTimeoutWarning) * 60 * 1000;
    setTimeout('SessionWarning()', sTimeout);

    function SessionWarning() {
        var message = "Your session will expire in another " +
            (parseInt(sessionTimeout) - parseInt(sessionTimeoutWarning)) +
            " mins! Please Save the data before the session expires";
        alert(message);
    }
</script>
atokpas
  • 3,231
  • 1
  • 11
  • 22
Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
  • 1
    I added `` in my Web.config file. How do I assign the `var sessionTimeoutWarnin`? – SearchForKnowledge Sep 05 '14 at 17:15
  • Implementing this kind of client-side code is possible open a security vulnerability issue ? – Fer R Jan 17 '18 at 19:24
  • @FerR what security issue are you thinking of? Are you concerned about the "<%=" references? – Jeff Mergler Feb 10 '18 at 00:30
  • 1
    @JeffMergler my QSA area encourages us (dev team) to avoid using Javascript or any client-side scripting to perform operations. Our web apps are part of a banking-core, so must meet with strong test cycles. My concern, for instance, is about if an atacker can alter or inject malicious code into client script and extend arbitrary the session. "<%=" is a potential vulnerability. – Fer R Feb 28 '18 at 20:39
7

This has been addressed before, e.g. ASP.NET - Javascript timeOut Warning based on sessionState timeOut in web.config

However, AFAIK there isn't a totally reliable way to do this, since:

  • If the user has more than one window open using the same session, then one window may be more recent than the other and the client session timeouts on the oldest window would be stale / incorrect.
  • If you round trip to the server to see what the current session expiration is, you will extend it, thus defeating the purpose of the popup / alert.
Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Can you please tell me, how to alert user for session timeout in MVC 4? Also I'm not using forms authentication. Is it possible without forms authentication? – Huma Ali May 15 '16 at 17:36
3

I went to see the article from the post of Pranay Rana, and I like the general idea, but the code could use some streamlining. So here is my version. For tablet / mobile issues see below:

<script language="javascript" type="text/javascript">
    var minutesForWarning = 4;
    var sessionTimeout = parseInt("@Session.Timeout"); // razor syntax, otherwise use <%= Session.Timeout %>
    var showWarning = true;

    function SessionWarning() {
        showWarning = false;
        alert("Your session will expire in " + minutesForWarning + " mins! Please refresh page to continue working.");
        // leave a second for redirection fct to be called if expired in the meantime
        setTimeout(function () { showWarning = true; }, 1000);
    }

    function RedirectToWelcomePage() {
        if (showWarning)
            alert("Session expired. You will be redirected to welcome page.");
        document.getElementById('logoutForm').submit();
        // window.location = "../Welcome.aspx"; // alternatively use window.location to change page
    }

    setTimeout('SessionWarning()', (sessionTimeout - minutesForWarning) * 60 * 1000);
    setTimeout('RedirectToWelcomePage()', sessionTimeout * 60 * 1000);
</script>

Well, on tablets or mobiles, you can't count on the setTimeout, as javascript execution is suspended when the device is locked or browser inactive. Instead, I'm doing a periodical check (in my case, I esteem every 10s to be enough):

<script language="javascript" type="text/javascript">
    function addMinutes(date, minutes) {
        return new Date(date.getTime() + minutes * 60 * 1000);
    }
    function remainingMinutes(date) {
        return Math.round((date - (new Date()).getTime()) / 60 / 1000);
    }

    var minutesForWarning = 5;
    var sessionTimeout = parseInt("@Session.Timeout");
    var showWarning = true;
    var showRedirect = true;
    var timeToWarn = addMinutes(new Date(), sessionTimeout - minutesForWarning);
    var timeToEnd = addMinutes(new Date(), sessionTimeout);

    function CheckTime() {
        if (showWarning && new Date() > timeToWarn && new Date() < timeToEnd) {
            showRedirect = false;
            showWarning = false;
            alert("Your session will expire in " + remainingMinutes(timeToEnd)) + " mins! Please refresh page to continue working.");
        }
        if (new Date() > timeToEnd) {
            if (showRedirect)
                alert("Session expired. You will be redirected to welcome page ");
            document.getElementById('logoutForm').submit();
            // window.location = "../Welcome.aspx"; // alternatively use window.location to change page
        }
        if (showRedirect == false)
            showRedirect = true;
    }

    setInterval(CheckTime, 10000);

</script>
Damian Vogel
  • 1,050
  • 1
  • 13
  • 19
1

Below is some JavaScript with jQuery to warn the user about ASP.NET Forms Authentication timeout and will redirect them to the login page if timeout is reached. It could be improved and adapted for session timeout as well. It will also reset the authentication timeout by "pinging" the server whenever the user interacts with the page by clicking, typing or resizing.

Note that this does add load to the server by pinging with every click, key press, resize but it's pretty minimal. Still, if you have many users typing away you will need to evaluate the impact. I couldn't think of another way to do this because the server has to be involved since that's where the timeout is expiring.

Also note that the timeout is not hard-coded in the JS. It get's the timeout from the server so you only need to maintain it in one place in Web.config.

(function ($, undefined) {

    if (!window.session) {

        window.session = {

            monitorAuthenticationTimeout: function (redirectUrl, pingUrl, warningDuration, cushion) {

                // If params not specified, use defaults.
                redirectUrl = redirectUrl || "~/Account/Login";
                pingUrl = pingUrl || "~/Account/Ping";
                warningDuration = warningDuration || 45000;
                cushion = cushion || 4000;

                var timeoutStartTime,
                    timeout,
                    timer,
                    popup,
                    countdown,
                    pinging;

                var updateCountDown = function () {
                    var secondsRemaining = Math.floor((timeout - ((new Date()).getTime() - timeoutStartTime)) / 1000),
                        min = Math.floor(secondsRemaining / 60),
                        sec = secondsRemaining % 60;

                    countdown.text((min > 0 ? min + ":" : "") + (sec < 10 ? "0" + sec : sec));

                    // If timeout hasn't expired, continue countdown.
                    if (secondsRemaining > 0) {
                        timer = window.setTimeout(updateCountDown, 1000);

                    }
                    // Else redirect to login.
                    else {
                        window.location = redirectUrl;
                    }
                };

                var showWarning = function () {
                    if (!popup) {
                        popup = $(
                            "<div style=\"text-align:center; padding:2em; color: black; font-color: black; background-color:white; border:2px solid red; position:absolute; left: 50%; top:50%; width:300px; height:120px; margin-left:-150px; margin-top:-90px\">" +
                                "<span style=\"font-size:1.4em; font-weight:bold;\">INACTIVITY ALERT!</span><br/><br/>" +
                                "You will be automatically logged off.<br/><br/>" +
                                "<span style=\"font-size:1.4em; font-weight:bold;\" id=\"countDown\"></span><br/><br/>" +
                                "Click anywhere on the page to continue working." +
                            "</div>")
                            .appendTo($("body"));

                        countdown = popup.find("#countDown");
                    }

                    popup.show();
                    updateCountDown();
                };

                var resetTimeout = function () {
                    // Reset timeout by "pinging" server.
                    if (!pinging) {
                        pinging = true;
                        var pingTime = (new Date()).getTime();
                        $.ajax({
                            type: "GET",
                            dataType: "json",
                            url: pingUrl,
                        }).success(function (result) {

                            // Stop countdown.
                            window.clearTimeout(timer);
                            if (popup) {
                                popup.hide();
                            }

                            // Subract time it took to do the ping from
                            // the returned timeout and a little bit of 
                            // cushion so that client will be logged out 
                            // just before timeout has expired.
                            timeoutStartTime = (new Date()).getTime();
                            timeout = result.timeout - (timeoutStartTime - pingTime) - cushion;

                            // Start warning timer.
                            timer = window.setTimeout(showWarning, timeout - warningDuration);
                            pinging = false;
                        });
                    }
                };

                // If user interacts with browser, reset timeout.
                $(document).on("mousedown mouseup keydown keyup", "", resetTimeout);
                $(window).resize(resetTimeout);

                // Start fresh by reseting timeout.
                resetTimeout();
            },
        };
    }

})(jQuery);

Simply call the above once when your page loads:

window.session.monitorAuthenticationTimeout(
        "/Account/Login",    // You could also use "@FormsAuthentication.LoginUrl" in Razor.
        "/Account/Ping");

On the server, you'll need an action that returns the remaining time. You could add more information as well.

    public JsonResult Ping()
    {
        return Json(new { 
                        timeout = FormsAuthentication.Timeout.TotalMilliseconds 
                    }, 
                    JsonRequestBehavior.AllowGet);
    }
moomoo
  • 826
  • 10
  • 9
0

You will have to use client side technology for here (javascript). Using for example you would use javascript timeout facility and then show the warning. If user clicks ok you can need to do something to keep the session alive. I would sugest using jquery.ajax method, and making a call to the server, can be a dummy call - just to keep the session alive.

Joseph Caruana
  • 2,241
  • 3
  • 31
  • 48
0

You could you jquery and the setinterval function to do an Ajax post behind the scenes to refresh the timeout, if using sliding expiration, or get the value of time remaing by recording the session start time and subtracting from the expiration time.

Samuel Goldenbaum
  • 18,391
  • 17
  • 66
  • 104
0

What you can do is use some javascript to fire the message. Use a timer to fire after a certain period (period set for session time out in your application - a couple of minutes).

After that period, show a confirmation dialog to the user that session will time out. If the user clicks to keep the sesion. Make a dummy postback in the page so that the session is not lost. You can also make an AJAX call so that user does not see the page reloading and loses input data.

Tanveer Badar
  • 5,438
  • 2
  • 27
  • 32