Hej Community,
I got stuck and I need some advice or pointer to a solution. I have a fairly simple Identity Server 4 Setup:
I would like to automatically log out the user after 10 minutes of inactivity. In the sample below I used 10 s to make testing somewhat quicker. The authentication, redirect and user enforced logout work as expected and like a charm using the code below. However, when the user idles for longer than the set 10 s, the user is still signed in and is not redirected to the login page at the IDS host.
The MVC client is setup using Hybrid Grant as:
Client Definition
var mvcClient = new Client
{
ClientId = "account-mvc",
ClientName = "Account MVC",
ClientUri = "https://localhost:5002",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets = { new Secret("secret".Sha256()) },
EnableLocalLogin = true,
RequireConsent = false,
AllowOfflineAccess = false,
AccessTokenLifetime = 10, // 10 s by intention
IdentityTokenLifetime = 10, // 10 s by intention
RedirectUris = "https://localhost:5002/signin-oidc",
PostLogoutRedirectUris = "https://localhost:5002/signout-callback-oidc",
FrontChannelLogoutUri = "https://localhost:5002/signout-oidc",
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
},
};
Identity Server Options
services.AddIdentityServer(options =>
{
options.Authentication.CheckSessionCookieName = "auth-cookie";
options.Authentication.CookieLifetime = new System.TimeSpan(0, 0, 10);
options.Authentication.CookieSlidingExpiration = false;
options.Csp.Level = IdentityServer4.Models.CspLevel.Two;
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
.Add... // Left out for brevity
In the Startup of the MVC client I add:
MVC Client Startup
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
options.ExpireTimeSpan = TimeSpan.FromSeconds(10);
options.SlidingExpiration = false;
options.Cookie.Name = "mvc-cookie";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:5001/";
options.ClientId = "account-mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
});
and added app.UseAuthentication()
in the Configure
method.
Question
How can I make sure that the user is signed out at the Identity Server once the session timed out? Any hint and help appreciated!
After more debugging I found that the cookie lifetime of the MVC client worked as intended with a sliding expiration. However, once the cookie expired, the Idenity Server (IDS) was contacted and the cookie was refreshed as the session was still alive / active at the IDS.
I figured two solutions from which I decided to use Solution 1 for now and see if it is the most suitable in the long-run.
If anyone has a comment or recommendation towards security and best practice please comment or post another solution.
The Client property UserSsoLifetime
(available in Identity Server 4 from v2.3
) can be used to set the maximum time until a user must re-authenticate to use the client. So for the sample of the question the only required addition is in the Client Definition by adding UserSsoLifetime = 10
, such as,
Client Definition
var mvcClient = new Client
{
ClientId = "account-mvc",
ClientName = "Account MVC",
ClientUri = "https://localhost:5002",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets = { new Secret("secret".Sha256()) },
EnableLocalLogin = true,
RequireConsent = false,
AllowOfflineAccess = false,
UserSsoLifetime = 10, // <- HERE
AccessTokenLifetime = 10, // 10 s by intention
IdentityTokenLifetime = 10, // 10 s by intention
RedirectUris = "https://localhost:5002/signin-oidc",
PostLogoutRedirectUris = "https://localhost:5002/signout-callback-oidc",
FrontChannelLogoutUri = "https://localhost:5002/signout-oidc",
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
},
};
This will force the user to re-authenticate after 10 s of inactivity.
This SO question solves the issue with an OIDC property which can be used to force the user to re-authenticate via the login prompt once the session expired - see @Scotty Brady's answer.
So for the example denoted in the question should look like the following. Note that only the MVC client needs changes, namely the Cookie lifetime was removed and OIDC options were added forcing the re-authentication and to use the token lifetime from IDS (each line marked with a // <- HERE
). This way, the cookie settings from IDS are used (sliding lifetime of 10s).
MVC Client Startup
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies") // <- HERE
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:5001/";
options.ClientId = "account-mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.UseTokenLifetime = true; // <- HERE
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Events.OnRedirectToIdentityProvider = context => // <- HERE
{ // <- HERE
context.ProtocolMessage.Prompt = "login"; // <- HERE
return Task.CompletedTask; // <- HERE
}; // <- HERE
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With