Search code examples
asp.netasp.net-coresingle-sign-onidentityserver4user-inactivity

How to handle idle session timeout across client apps and Identityserver4


I got stuck and need some advice or pointer to a solution. I have a fairly simple IdentityServer4 setup for our single sign on Implementation.

Three Apps

IdentityServer4 with asp.net core identity (ID server)

ASP.NET Core 2.2 MVC (client1)

ASP.NET Core 2.2 MVC (client2) The MVC client is setup using Hybrid Grant

Two scenarios:

  1. If user is active in any one of the clients(example is client1) then user should not be logged out in client2 after reaching idle timeout in that app(client2).
  2. If user is inactive in both the clients(client1 and client2) then System should log out user from all the clients(client1 and client2) when idle timeout exceeds.

Scenario 1: User active in any one of the clients. User active in client1 and idle in client2 Expected behavior: System should not log out from client2 when idle timeout exceeds. Current Identity Behavior: Able to continue works in client1, but client2 and ID server navigates to login page after idle time exceed.

Scenario 2: User is inactive in all 2 clients (client1 and client2) Expected behavior: System should log out user from the all 2 clients and ID server when idle timeout exceeds.

If I set cookie expire time in ID server only (removed slidingexpiration is true and cookie expire time in both client1 and client2) then the client apps are working continuously without expire time even though both the clients are idle until ID server expire time exceeds, client apps are working continuously.

I would like to know if expected behavior can be achieved

Clients:

 .AddCookie(options =>
                {
                    // Configure the client application to use sliding sessions
                    options.SlidingExpiration = true;
                    // Expire the session of 15 minutes of inactivity
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(15);
                })

ID server:

services.AddIdentityServer(options =>
            {
                options.Authentication.CookieLifetime = TimeSpan.FromMinutes(15);
                options.Authentication.CookieSlidingExpiration = true;
            })

Solution

  • The question that needs to be answered first is: what system, where?

    The browser clients can't be trusted and should not interfere. I think it's best to restore the cookie settings. Don't let the front try to trigger a logout.

    It's best to keep track of the users in the backend. You can accomplish this by adding a service in the Mvc client that 1. registers the user as active by IdentityServer, 2. keeps track of activity and 3. unregisters the user by IdentityServer when the user seems inactive too long. Take a look at the token cleanup service that comes with IdentityServer for some inspiration on how you can update the list using an interval.

    In startup of both the Mvc clients add a handler for the cookies:

    Services
        .AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies", options =>
        {
            // you'll need to create your own handler
            options.EventsType = typeof(MyCookieEventHandler);
        })
    

    I won't add code here but rather explain the purpose: the cookiehandler is called every time a user needs to access a secured source. This means that you can update the users activity timestamp (that you use to keep track of the user) here, meaning that you don't have to contact IdentityServer all the time. The service should contact IdentityServer only when there is a status change: user has become active or inactive.

    Now you need to add a service to IdentityServer in order to keep track of the users in a central place. You can persist the status of the user in a store. Add a user (per client) when it becomes active and remove the user when it is no longer active. When the last session of a user is removed from this list, trigger a backchannel logout.

    A backchannel logout can signal the mvc clients that a user is logged out. Using the CookieEventHandler the user is then denied access. This doesn't update the front on logout, but is effective when the user contacts the mvc client. It will find itself logged out of all apps and Identityserver.

    When you follow the link you'll see an implementation of the CookieEventHandler. And search the internet for backchannel logout, you may find examples that you can use.