Identity: ASP.NET core 2.0 Authentication does persist more than 30 minutes.

Created on 23 Aug 2017  路  14Comments  路  Source: aspnet/Identity

I do not manage to keep users logged in for more than 30 minutes.

Lets take default Visual Studio example "ASP.NET Core Web Application" -> .NET Framework 4.6.1 + ASP.NET Core 2.0 + MVC + Individual User Accounts.

ConfigureServices:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();

Configure:
app.UseAuthentication();

Action Login:
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);

If user logs in + remember me (isPersistent = true) user gets rejected after 30 minutes. You can navigate between pages or reopen browser during those 30 minutes and everything is ok. But after 30 minutes you are asked to login again.聽

Setting this does not solve the problem:
services.ConfigureApplicationCookie(options => { 聽 options.ExpireTimeSpan = TimeSpan.FromDays(1); });

Most helpful comment

Is services.ConfigureApplicationCookie defined before or after the services.AddIdentity? If you define it before the services.AddIdentity, your custom values will be overwritten.

And this is how you can change the ValidationInterval interval:

services.Configure<SecurityStampValidatorOptions>(options =>
            {
                // enables immediate logout, after updating the user's stat.
                options.ValidationInterval = TimeSpan.Zero;
            });

All 14 comments

Can you check the security stamp column for your users? 30 minutes is the default timespan for the cookie to be rechecked against the security stamp for the user, i.e. if the user changes his password, that will expire all login cookies...

https://github.com/aspnet/Identity/blob/dev/src/Microsoft.AspNetCore.Identity/SecurityStampValidatorOptions.cs#L20

If there is something wrong with the security stamp storage for your users, this would cause what you are seeing

Thanks for reply. How should I identify a problem with security stamp?
In my database it looks like this:
capture
Then I mention 30 minutes, nothing is done during this interval that could change password or any of user data. I just refresh the page.
Edit: Should I change the default ValidationInterval and how? if this is safe to change it

You can try nulling out the security stamp validator logic to see if that fixes the issue to start:

services.ConfigureApplicationCookie(o => o.Events = new CookieAuthenticationEvents())

ok. after setting this I got logged out in 2 minutes 30 seconds.

What does the cookie header actually look like?

By saying cookie header you mean this:
capture2

Is there a place somewhere to set options.SecurityStampValidationInterval in ASP.NET Core 2.0?
This option was previously available in services.AddIdentity<>(options =>...) in ASP.NET Core 1.1.

Is services.ConfigureApplicationCookie defined before or after the services.AddIdentity? If you define it before the services.AddIdentity, your custom values will be overwritten.

And this is how you can change the ValidationInterval interval:

services.Configure<SecurityStampValidatorOptions>(options =>
            {
                // enables immediate logout, after updating the user's stat.
                options.ValidationInterval = TimeSpan.Zero;
            });

Strange things happens... My current CofigureServices method looks like this:

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
        services.Configure<SecurityStampValidatorOptions>(options =>
        {
            // enables immediate logout, after updating the user's stat.
            options.ValidationInterval = TimeSpan.Zero;
        });
        services.AddMvc();

and i can login. TimeSpan.Zero does not behave as you have written.

Thank you @VahidN and @HaoK . Setting ValidationInterval to more than 30 minutes, seems to solve the problem.
options.ValidationInterval = TimeSpan.FromHours(12);

However, options.ValidationInterval = TimeSpan.Zero; does not work as you have noted; user does not get logged out instantly.

Now if you would not mind, please explain me shortly how does this ValidationInterval work. Is it global for the whole webapplication? I mean that:

  • when i start web app it does a check every 12 hours for all users
  • or is it user specific and starts counting since user login?

And since options.ValidationInterval is no longer under services.AddIdentity, I would expect to find this change mentioned in https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x

SecurityStampValidator will be called for every single request to the server, but it will decide based on the ValidationInterval value and cookie issue time to determine when it should check the validity of the cookie again. If you set the ValidationInterval to zero, it will check and call the ValidateSecurityStampAsync method every time. So it's not related to the ExpireTimeSpan value. It's about the SecurityStamp property value of the current user. This value (SecurityStamp) will be changed internally by the framework if you update the user's properties.
If you call services.ConfigureApplicationCookie after the services.AddIdentity, you can change the default value of the ExpireTimeSpan. Because the AddIdentity method sets the default cookie's settings too.

It seems there was a big gap in my understanding about how does this all work. I also found that I have lied a little. So to finish up for other as stupid as me.

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();
services.Configure<SecurityStampValidatorOptions>(options => options.ValidationInterval = TimeSpan.FromSeconds(10));
services.AddAuthentication()
    .Services.ConfigureApplicationCookie(options =>
    {
        options.SlidingExpiration = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
    });

According my understanding this works like this:

  • the check if user is logged happens ~every 10 seconds, depending on requests ratio. Server checks security stamps upon every request to the server options.ValidationInterval = TimeSpan.FromSeconds(10)).
  • cookie is valid at minimum for 30 minutesoptions.ExpireTimeSpan = TimeSpan.FromMinutes(30);, but can be extended with options.SlidingExpiration = true; if page is refreshed or navigated.
  • important! do not be too "smart" like me and do no run _userManager.UpdateSecurityStampAsync(user); just after successful login. Because this updates security stamp and next options.ValidationInterval validation will fail.

I had this problem as well when updating to 2.0, but the cause was that I using signInManager.SignInAsync with a non existent user (I'm handling the logins manually using an API, not a good idea).
I'm not using existent users and it works fine when setting the cookie opt ExpireTimeSpan to higher than 30 minutes.

@gtarsia
I had this problem when I am using Cookie authentication without identity setup. Does anyone know what is the maximum value for the ValidationInterval. I set it like 7 days, but it expires already in 30 minutes or redirected me to log in page.

` services.AddAntiforgery(options =>
{
options.Cookie.Expiration = TimeSpan.FromDays(1);

            options.Cookie.Name = "M";
            options.HeaderName = "VerificationTkn";
        });

        services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                //options.DefaultChallengeScheme =  CookieAuthenticationDefaults.AuthenticationScheme;
            })

        .AddCookie(
            CookieAuthenticationDefaults.AuthenticationScheme,
            options =>
            {
                options.Cookie.Expiration = TimeSpan.FromDays(1);
                options.ExpireTimeSpan = TimeSpan.FromDays(1);
                options.LoginPath = "/Account/Index";
                options.LogoutPath = "/Account/SignOut";
                options.ReturnUrlParameter = "ReturnUrl";
                //options.Events.OnRedirectToLogin = context =>
                //{

                //    context.Response.Headers["Location"] = context.RedirectUri;
                //    context.Response.StatusCode = 401;
                //    return Task.CompletedTask;
                //};

            });

        services.Configure<SecurityStampValidatorOptions>(options =>
        {
            // enables immediate logout, after updating the user's stat.
            options.ValidationInterval = TimeSpan.FromDays(1);
        });


        services.AddMvc();`

In my AccountController.cs:

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, items, new AuthenticationProperties { AllowRefresh = true, IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddDays(1) });

Hi,

I've struggled on this a bit too and I've found that for SecurityStampValidator can validate your security stamp:

  • Your user store has to implement IUserSecurityStampStore
  • You have to have security stamp claim in your principle.

Then you can set ValidationInterval to any value suitable to validate the security stamp.

Hope it will help someone like me wondering why the session does not keep more than 30 minutes 馃槂

Was this page helpful?
0 / 5 - 0 ratings