I'm using IdentityServer4 (v3.1.x) with the Entity Framework package to allow the configuration and operational settings to be stored in a database. I've noticed however that for -some- reason the duration of which users are logged in to IS4 is determined by the IIS Application Pool 'recycle interval' setting, which I've currently set at 30 minutes. This is different from the expected behavior, of the users' session being as long as the access_token duration / refresh_token duration allows for.
When the IIS Application Pool 'recycle interval' is set to a higher value (1740 minutes max), the problem disappears. What I expect however is for the 'session' (for the lack of a better name) to be persistent between application pools and application pool recycles.
What am I doing wrong, and what do I need to change to make it work?
Durations:
- IdentityTokenLifetime: 300s / 5m
- IdentityAccessToken: 300s / 5m
- AuthorizationCodeLifetime: 300s / 5m
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
string connectionString = _config.GetValue<string>("ConnectionStrings:IdentityServerDBConnectionString");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<IdentityServerDBContext>(x => x.UseSqlServer(connectionString));
var builder = services.AddIdentityServer(
options => {
options.Authentication.CookieLifetime = TimeSpan.FromDays(14); // As test
}
)
.AddSigningCredential(LoadCertificate())
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddProfileService<ProfileService>();
// Custom implementations
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
services.AddTransient<IProfileService, ProfileService>();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(o =>
{
o.SlidingExpiration = false;
o.ExpireTimeSpan = TimeSpan.FromDays(14); // As test
});
services.AddAuthorization();
}
*EDIT: As Tore points out in the comment below, the missing DataProtection implementation was the cause of the issue.
Using the links he shared I was able to solve it by adding the Microsoft.AspNetCore.DataProtection package, and adding the following snippet to the Startup:
// Persistent data protection
services
.AddDataProtection()
.PersistKeysToDbContext<DBContext>();
CodePudding user response:
The cookies are encrypted using the Data Protection APIs in ASP.NET Core and for production it is wise to configure this properly, so the encryption key/key-ring is persisted outside your web-application.
I did blog about the data protection API here:
See also these links: