.NET 6 Session TimeOut - c#

I am trying to set the session timeout to 30 mins in .NET 6.
I added the following code for it.
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
options.IdleTimeout = TimeSpan.FromMinutes(30));
It is not working and the session is expiring in a few minutes.

When session is expired, the server will delete all session variables set on login and there is no way to see if it has been expired from client side (one of the many reasons on why I switched from Sessions to JsonWebTokens).
To use session, add following code in your Program.cs
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.Cookie.HttpOnly = true;
// make the session cookie Essential
// so that session variable is not null
// check this StackOverflow answer: https://stackoverflow.com/a/64984796/19112855
options.Cookie.IsEssential = true;
});
app.UseSession(); // before app.UseAuthentication(); and after app.UseRouting();
To manually delete all session variables, call this in your controller HttpContext.Session.Clear();

Related

C# ASP.NET Core 6 MVC : authentication timeout not triggering

I am having some weird issues with authentication in my app. To preface, it is a C#, ASP.NET Core 6 MVC web app. Users log in and all controllers have an [Authorize] tag.
I am making use of sessions to determine what menu options to show the users and this is working as far as I can tell when the session timer ends. My issue is with the users that are logged in, I'm not using anything special, just the built in Identity provider reading from the SQL Server.
What happens is the authentication never times out even after I stop running the application and start it again, the previously logged in user is displayed as being valid as opposed to making me log in again. I have looked at a number of other questions and articles and based on what I've been seeing I have added the following code to the Program.cs file.
For the basis of testing I made the idle timeouts just 2 minutes for both authentication and sessions. My session does expire after 2 minutes but the authentication never expires.
Can anyone point me in the right direction or tell me what I'm doing wrong?
Thanks!
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(2);
options.AccessDeniedPath = "/Home/Index/";
options.LoginPath = "/Home/Index/";
options.LogoutPath = "/Home/Index/";
options.Cookie.Expiration = TimeSpan.FromMinutes(2);
options.Cookie.Name = ".TOR";
});
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(2);
options.Cookie.Name = ".TORSession";
options.IOTimeout = TimeSpan.FromMinutes(2);
});

Set authentication token expiry in ASP.NET Core 6.0 MVC

I've got a website directly from Microsoft's ASP.NET Core 6.0 MVC web app template with "Authentication type" set to "Individual Accounts".
How do I set the expiration of the authentication token, preferably with a rolling value?
According to the docs, you'd add something like the following in:
builder.Services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
From the docs about ExpireTimeSpan:
Controls how much time the authentication ticket stored in the cookie will remain valid from the point it is created
The expiration information is stored in the protected cookie ticket. Because of that an expired cookie will be ignored
even if it is passed to the server after the browser should have purged it.
This is separate from the value of Microsoft.AspNetCore.Http.CookieOptions.Expires, which specifies how long the browser will keep the cookie.
In other words, while it doesn't set the cookie itself with an expiration value, the ExpireTimeSpan and SlidingExpiration settings will cause the application to provide a new value in responses around every 5 minutes and update within the protected cookie value the new expiration.

.net 6 Session Cookies don't persist in Chrome

Everytime I try to set the session cookies for a Chrome session, the cookies are not saved.
The session cookies work in Firefox though.
I think it either has something to do with allowing SameSite cookies or that secure cookies don't persist over HTTP.
Here is the code I use to add them:
services.AddDistributedMemoryCache();
services.AddSessions(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SameSite = SameSiteMode.None;
options.Cookie.SecurePolicy = CookieSecurePolicy.None;
options.Cookie.Domain = "localhost";
});
services.AddHttpContextAccessor();
I only use the code above for dev purposes.

Signed In Principal but User.Identity.IsAuthenticated is False and HttpContext.AuthenticateAsync is False

I have logged in manually to a .NET Core 3 Web API app as seen in the controller action below. No matter what I try, I can't seem to get the .NET framework to recognize that the application user is logged in. I am testing locally in Visual Studio, but this behavior is also reflected when I test on a server as well. Why isn't the principal that I have created and used in the HttpContext.SignInAsync method being sent to the middleware (at least it seems as though it is not)?
Note: I have seem some posts where users say you have to sign in and then make another request to the server for the new principal to take effect. I have tried this but the result is the same.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//........
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = DefaultAuthenticationTypes.ApplicationCookie;
})
.AddCookie(DefaultAuthenticationTypes.ApplicationCookie, options =>
{
// true by default
options.SlidingExpiration = true;
// 14 days by default
options.ExpireTimeSpan = TimeSpan.FromMinutes(120);
options.Cookie.IsEssential = true;
options.Cookie.HttpOnly = true;
options.Cookie.SameSite = SameSiteMode.None;
options.LoginPath = "/Login";
options.LogoutPath = "/Logout";
});
services.AddAuthorization();
//........
}
public void Configure(IApplicationBuilder app)
{
//........
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseCors();
//........
}
Controller Action:
ClaimsIdentity userIdentity =
new ClaimsIdentity(jwtSecurityToken.Claims, DefaultAuthenticationTypes.ApplicationCookie);
ClaimsPrincipal principal =
new ClaimsPrincipal(userIdentity);
await HttpContext.SignInAsync(DefaultAuthenticationTypes.ApplicationCookie, principal,
new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddDays(7)
});
AuthenticateResult authenticateResult =
await httpContext.AuthenticateAsync(DefaultAuthenticationTypes.ApplicationCookie);
//This always returns false!!!
User.Identity.IsAuthenticated
//This always returns false!!!
I hate to do this, but this code actually works. If you hit this code via the browser directly, the code logs you in as expected and it all works as expected.
What I was trying to do was get it to work via a Vue.js front end app using a .NET Core 3 Web API 2 app on the backend. For some reason, the Vue app cannot log the backend app in. When on a Vue front page and I hit the API action to login via Vue code, the .NET code logs in with no errors, but on any other call from the VUE app, the .NET app says that the user is unauthorized. I suspect that there is something going on with how the cookie is stored and data privacy around the cookie.
In the context of this question, this code works as expected. Thank you.

Cookie Authentication Early Expiration

Issue
In my ASP.NET MVC Core 2.0 application I have setup to use the cookie authentication scheme without using Identity as we have our own backend authentication storage and api.
The authentication and authorization works perfectly every time.
However, no matter what the login/session expires after approximately 30 minutes. You can see that we are setting the timeout to 120 minutes for both authentication cookie and session cookie.
Application information:
Platform: .Net 4.7.x (Windows)
Framework: Asp.Net Core 2.x
IIS used as a proxy server
Any help or input on how to solve this would be welcome
Code
Update: Replaced services.AddMemoryCache() with services.AddDistributedRedisCache(..) - testing to see how this works
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "CoreTestInstance";
});
services.AddAuthentication("CookieAuthenticationScheme")
.AddCookie("CookieAuthenticationScheme", options =>
{
options.Cookie.Name = authSettings.Name;
options.Cookie.HttpOnly = false;
options.Cookie.Expiration = TimeSpan.FromMinutes(120);
options.ExpireTimeSpan = TimeSpan.FromMinutes(120);
options.AccessDeniedPath = new PathString("/Errors/StatusCodeErrors/401");
options.LoginPath = "/Account/Login";
});
// services.AddMemoryCache();
services.AddSession(options =>
{
options.Cookie.Name = sessSettings.Name;
options.Cookie.HttpOnly = false;
options.IdleTimeout = TimeSpan.FromMinutes(120);
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Errors/Default");
}
app.UseStatusCodePagesWithRedirects("/Errors/StatusCodeErrors/{0}");
app.UseStaticFiles();
app.UseAuthentication();
app.UseSession();
app.UseMvc();
}
AccountController.cs
[HttpPost("Login")]
public async Task<IActionResult> Login(AccountModel model)
{
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, model.UserName));
claims.Add(new Claim(ClaimTypes.Role, "Administrator", ClaimValueTypes.String, model.UserName));
var identity = new ClaimsIdentity(claims, "login");
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync("CookieAuthenticationScheme", principal);
}
You're using in-memory sessions, which are tied to the process. That process in IIS is your App Pool. By default, the App Pool recycles automatically after a period of time. When it recycles, it takes your sessions with it.
Use a persistent session store: SQL Server, Redis, etc. (Sessions use distributed cache, so the way you set up persistent sessions is to setup a persistent distributed cache store.)
Thanks to Chris Pratt to starting me in the right direction. Moving to Redis helped with performance and distributed caching is the right way to go.
However, Redis did not solve my problem, the app still timed out after 90 minutes regardless of my settings.
Since we use IIS I ended up having to change settings in the AppPool to finally get the session to honor my timeout instead of the AppPool's.
For the AppPool, click on the Advanced Settings and make the following changes:
Section: Process Model
Idle Time-out (minutes) = 0 (disables the timeout so that the application pool will never shut down due to being idle)
Idle Time-out Action = Suspend (A suspended worker process remains alive but is paged-out to disk, reducing the system resources it consumes)
Section: Recycling
Regular Time Interval (minutes) = 0 (setting to 0 means the apppool will not recycle)
Note: The above settings should not affect other applications unless you have a great deal many applications running on the same server. I suggest you research the settings in detail before using them to ensure they will work for you.
Finally, I ran several tests with various settings (we store them in appsettings.json) for timeout from 2 mins, 10 mins, 1 hour and finally 2 hours and all worked as required.

Categories