No matter what I've tried I can't seem to increase the time required between logins more than 20 ~ 30 minutes. This is even if the user is continuously active - so this is not just "idle" time it's maximum time between logins. After 20 minutes the user is redirected to the login page to login again.
The strange thing is that when I decrease the CookieOptions.ExpireTimeSpan to something like 10 seconds, it redirects after 10 seconds as expected. I also tested the SlidingExpiration and that works too - using the lower ExpireTimeSpan, anything larger than 20/30 minutes doesn't seem to work.
I thought this might have something to do with my host server's application pool settings. Maybe the application pool dies after 20 minutes causing the login to be invalid but it happens even when I run the application straight from Visual Studio.
I'm honestly out of ideas and I don't even know how to debug this if this is a cookie issue. I'd really appreciate any help even if there's a way to read the ExpireTimeSpan value on the cookie after login.
This is my code currently on Startup:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
//services.AddSingletons, Transients etc..
services.AddIdentity<IdentityUser, IdentityRole>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
// Password settings.
// Lockout settings.
// User settings.
});
services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/Login";
//sliding expiration doesn't seem to work, nor does expiretimespan
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromHours(1);
});
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
config.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddHttpContextAccessor();
}
My Configure:
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
I login using this:
[HttpPost]
[Route("/Login")]
[AllowAnonymous]
public async Task<ActionResult> Login(string returnUrl, LoginFormModel loginFormModel)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid) {
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(loginFormModel.Username, loginFormModel.Password, loginFormModel.RememberMe, lockoutOnFailure: true);
if (result.Succeeded) {
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
}
}
Would really be grateful for any tips! Thanks!
See a similar issue here and the bug report here.
In short, it's a bug in ASP.NET Core 2.1 if you are implementing your own IUserStore but not implementing IUserSecurityStampStore, the user is logged out after 30 minutes, even though the cookies did not expire.
A quick fix is increasing the security stamp validation to a safe-enough value like so:
services.Configure<SecurityStampValidatorOptions>(o => o.ValidationInterval = TimeSpan.FromHours(10));