How to change ".AspNetCore.Identity.Application" cookie expiration?

14,581

Solution 1

As Kirk Larkin said ".AspNetCore.Identity.Application" cookie is probably set by the Identity Server application that make use of Asp.Net Identity. So if you want to manage the user session on the IS4 app you need to configure it there.

IS4 application: ".AspNetCore.Identity.Application" cookie.

If you use Identity to configure the cookie as persistent you need to set the expiration when you sign in the user.

var props = new AuthenticationProperties {
  IsPersistent = true,
  ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
await HttpContext.SignInAsync(userId, userName, props);

If you don't set IsPersistent=true then the cookie has session lifetime and you can set the contained authentication ticket expiration like this:

.AddCookie(options => {
    options.Cookie.Name = "idsrv_identity";
    options.ExpireTimeSpan = TimeSpan.FromHours(8);
    options.SlidingExpiration = true;
  });

Your client application: : ".AspNetCore.Cookies" cookie.

services.ConfigureApplicationCookie isn't called because if you use .AddCookie(...) this takes the precedence. The options are the same.

This set the app cookie as session.

.AddCookie(options => {
    options.Cookie.Name = "myappcookie";
    options.ExpireTimeSpan = TimeSpan.FromHours(8);
    options.SlidingExpiration = true;
  });

A way to make the app cookie persistent using OIDC is to set the expiration in the OnSigningIn event in AddCookie.

options.Events.OnSigningIn = (context) =>
{
    context.CookieOptions.Expires = DateTimeOffset.UtcNow.AddDays(30);
    return Task.CompletedTask;
};

A note about user session.

Every situation is different, so there isn't a best solution, but remember that you have to take care of two user session. One on the IS4 app and one on your client app. These can go out of sync. You need to think if a persistent user session on your client app make sense. You don't want that your user remains logged in your client app when the central SSO (single sign-on) session is expired.

Solution 2

After scrambled through the both AspNetCore 3.1 & IdentityServer 4.0.4 repo, I found the working way to set default authentication cookie option .

TD;LR:

    // in Startup.ConfigureService(IServiceCollection services)
    services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, option =>
    {
        option.Cookie.Name = "Hello"; // change cookie name
        option.ExpireTimeSpan = TimeSpan.FromSeconds(30); // change cookie expire time span
    });

Full Setup:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.AddRazorPages();

        // cookie policy to deal with temporary browser incompatibilities
        services.AddSameSiteCookiePolicy();
        services.AddDefaultAllowAllCors();

        // setting up dbcontext for stores;
        services.AddDbContext<ApplicationDbContext>(ConfigureDbContext);

        services
            .AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.SignIn.RequireConfirmedAccount = true;
            })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultUI()
            .AddDefaultTokenProviders();

        // read clients from https://stackoverflow.com/a/54892390/4927172
        var builder = services.AddIdentityServer(options =>
        {
            options.Events.RaiseSuccessEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.UserInteraction.LoginUrl = "/identity/account/login";
            options.IssuerUri = _configuration.GetValue<string>("IdentityServer:IssuerUri");
        })

            .AddAspNetIdentity<ApplicationUser>()
            .AddDeveloperSigningCredential()
            .AddConfigurationStore<ApplicationConfigurationDbContext>(option => option.ConfigureDbContext = ConfigureDbContext)
            .AddOperationalStore<ApplicationPersistedGrantDbContext>(option => { option.ConfigureDbContext = ConfigureDbContext; })
            .AddJwtBearerClientAuthentication()
            .AddProfileService<ApplicationUserProfileService>();

        services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, option =>
        {
            option.Cookie.Name = "Hello";
            option.ExpireTimeSpan = TimeSpan.FromSeconds(30);
        });
        services.AddScoped<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, EmailSender>();
        services.Configure<SmsOption>(_configuration);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // use this for persisted grants store
        InitializeDatabase(app);

        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseDefaultAllowAllCors();

        app.UseStaticFiles();

        app.UseRouting();

        app.UseIdentityServer();

        app.UseAuthorization();


        app.UseStatusCodePages(async context =>

        {
            var response = context.HttpContext.Response;

            if (response.StatusCode == StatusCodes.Status401Unauthorized ||
                response.StatusCode == StatusCodes.Status403Forbidden)
                response.Redirect("/identity/account/login");

            if (context.HttpContext.Request.Method == "Get" && response.StatusCode == StatusCodes.Status404NotFound)
            {
                response.Redirect("/index");
            }
        });

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapRazorPages();
        });
    }

Solution 3

Adding this line before services.AddAuthentication is what worked for me eventually with IS4, taken from this github issue:

services.ConfigureApplicationCookie(x =>
{
       x.ExpireTimeSpan = TimeSpan.FromDays(1);
});
Share:
14,581

Related videos on Youtube

zdev
Author by

zdev

Updated on June 04, 2022

Comments

  • zdev
    zdev almost 2 years

    I'm using ASP.NET Core with Identity Server and Open Id Connect as described here. I need to change the time of authentication cookie expiration when the Remember Me option is set (14 days by default). I can see that the cookie named ".AspNetCore.Identity.Application" is responsible for that. I'm trying to set the expiration like this:

    .AddCookie(options =>
    {
        options.Cookie.Expiration = TimeSpan.FromDays(1);
        options.ExpireTimeSpan = TimeSpan.FromDays(1);
    })
    

    But it affects another cookie named ".AspNetCore.Cookies" (containing the same token value), which has Session expiration and doesn't seem to do anything. All the ways to change expiration that I found modify only the ".AspNetCore.Cookies" cookie, I couldn't find any way to modify the ".AspNetCore.Identity.Application" cookie. (By the way, the services.ConfigureApplicationCookie method isn't triggered for me at all for some reason).

    Could anyone please explain what is the difference between these two cookies and how can I modify the ".AspNetCore.Identity.Application" expiration?

    My code in Startup.ConfigureServices

    services.AddMvc(options =>
    {
        // ...
    })
    
    services.AddAuthorization(options =>
    {
        options.AddPolicy(PolicyNames.UserPolicy, policyBuilder =>
        {
            // ... 
        });
    });
    
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
    
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie(options =>
    {
        options.AccessDeniedPath = "/AccessDenied";
        options.SlidingExpiration = true;
    })
    .AddOpenIdConnect("oidc", options =>
    {
        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.Authority = "<authority>";
        options.RequireHttpsMetadata = false;
        options.ClientId = "<id>";
        options.ClientSecret = "<secret>";
        options.ResponseType = "code id_token";
        options.SaveTokens = true;
        options.GetClaimsFromUserInfoEndpoint = true;
        // ...
    });
    
    services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.Name = "MyCookie";
        options.Cookie.Expiration = TimeSpan.FromDays(1);
        options.ExpireTimeSpan = TimeSpan.FromDays(1);
    });
    
  • Gopal Zadafiya
    Gopal Zadafiya about 4 years
    how this works for external users ? _signInManager.ExternalLoginSignInAsync(loginProvider, providerKey, isPersistent: false, true); is the method that does not contain parameter to set expiration time as like for local users
  • sevenmy
    sevenmy about 4 years
    @GopalZadafiya This example use IdentityServer so the external login is managed in the IdentityServer app not in the client. But in general you can set the expiration in configuration, for example in AddIdentity if you use Identity or in AddCookie or AddCookieAuthentication. Never used external login, so I can't be more specific, check the asp.net core docs.