SYSK 304: How to detect and handle form-based authentication timeout during ASP.NET script callback

First thing first – if you’re not familiar with ASP.NET script callbacks, make sure to check out http://msdn2.microsoft.com/en-us/library/ms178208.aspx.

 

Now, what happens if the authentication token times out right before the client makes an asynchronous call to the server?

 

Will your error callback function be invoked? Unfortunately, the answer is ‘no’.

Will your success callback function be invoked? And answer again is ‘no’.

So, what will you see? You won’t see anything – it’ll be like the call never happened… If you use a tool like Fiddler or HttpAnalyzer, you should see that the client receives the 302 (redirection) result code with the redirect location pointing to the login page, but the user is not redirected to the login page.

 

Note: You may want to set the authentication cookie timeout to a very small number (e.g. 1 minute) for testing purposes:

<authentication mode="Forms">

    <forms defaultUrl="login.aspx" loginUrl="login.aspx" timeout="1"></forms>

</authentication>

<authorization>

    <deny users="?"/>

</authorization>

 

The reason for this behavior is the following “plumbing” code that actually receives the callback results:

 

function WebForm_ExecuteCallback(callbackObject)

{

    var response = callbackObject.xmlRequest.responseText;

    if (response.charAt(0) == "s")

    {

        . . .

    }

    else if (response.charAt(0) == "e")

    {

        if ((typeof(callbackObject.errorCallback) != "undefined") && (callbackObject.errorCallback != null)) {

            callbackObject.errorCallback(response.substring(1), callbackObject.context);

        }

    }

    . . .

}

Since the first character of the received response is neither “s” nor “e”, the fact that the result code is not 200 (OK) is simply ignored.

 

So, what can you do about it?

 

While I wouldn’t call the proposed solution below elegant, to me, it’s more of a hack than a solution, it’s the best I could think of at the time.

 

Basically, you do two things:

 

  1.  Add the following code to Global.asax:

void Application_AuthenticateRequest(object sender, EventArgs e)

{

    if (Request.IsAuthenticated == false && Request.RequestType == "POST" && Request.Params["__CALLBACKID"] != null)

    {

        Response.Write("elogin");

        Response.End();

    }

}

 

  1.  Add custom handling of the error response that contains the word “login”:

function OnErrorCallBack(result, context)

{

    if (result == 'login')

    {

        // TODO: Add your logic to handle login

        alert('authentication cookie expired');

    }

}