Cookie Authentication Expiring Too Soon in ASP.NET Core

Cookie Authentication expiring too soon in ASP.NET Core

users are being prompted to log back in after being idle for an hour
or less, and loosing work.

I have similar configuration, but it works fine for me.

One thing I can think of is you cannot let web server idle for 20 minutes. IIS's app pool default idle time-out is 20 minutes (I could not say for other Linux web server).

So you could either set longer app pool time-out (0 for infinity), or ping every 5 minutes from external service like Monitis.

enter image description here

Cookie Authentication Early Expiration

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.)

Cookie expires or session timeout too soon

A couple of thoughts before I go into a possible solution of why your logins are expiring. First, the FormsAuthentication cookie and SessionState are two different things completely. You can have one or the other, or both or neither. As a result, the timeouts for these two items are also not related.

The FormsAuthentication cookie is an encrypted cookie that contains some basic information such as the user name and an expiration value. The .NET application uses this cookie once a user has authenticated to know if the user is authorized for certain resources.

What controls the encryption and decryption of the FormsAuthentication cookie is the MachineKey for that web application on IIS. The MachineKey is a set of keys used to encrypt and decrypt the cookie. By default, a web application on IIS is set to AutoGenerate the machine key. What this means is that when an application starts, a random machine key is generated. If an application recycles, you get a new machine key. Additionally, if you are hosting on a shared provider, the web host will typically have your application load balanced, meaning hosted by more than one server. Each one of those servers will auto generate a machine key.

If your web application is on a load balanced scenario, then each machine in the web farm cannot decrypt the other's encrypted cookie. This will give the appearance of "being logged out". The example of this is logging in on web server A, then a subsequent request goes to web server B. Web server B does not share a machine key with web server A and cannot decrypt the cookie, sending the user back to the login page.

The solution is to define the MachineKey section in your web.config so each instance of IIS will use the same keys as well as if the application pool recycles, you still have the same machine key.

Here would be an example machine key (use the .NET 2.0 version) that you could place in your web.config

<system.web>
<machineKey validationKey="EBC1EF196CAC273717C9C96D69D8EF314793FCE2DBB98B261D0C7677C8C7760A3483DDE3B631BC42F7B98B4B13EFB17B97A122056862A92B4E7581F15F4B3551"
decryptionKey="5740E6E6A968C76C82BB465275E8C6C9CE08E698CE59A60B0BEB2AA2DA1B9AB3"
validation="SHA1" decryption="AES" />
</system.web>

Additional thoughts are that your expiration in your web.config (2880) and what you are actually setting the expiration to be (120) do not match. You may want them both to match.

What is the correct way to set a cookie expiration when using Azure AD to login users to an ASP.NET Core 5 Web Application?

I figured it out after stumbling across the following post:

https://brokul.dev/authentication-cookie-lifetime-and-sliding-expiration

There was another post on SO that I found that mentioned there are two types of cookies being set: session and authentication. Unfortunately, I closed the page before figuring this all out, so I am unable to properly cite it.

Anyways, the problem boiled down the fact that I was missing the authentication cookie's MaxAge property.

I added some rather verbose comments to point of observer, and unwanted, behavior when experimenting with different configs. I decided that this provides the best user experience while also eliminating correlated and nonce cookies (i.e., cookieAuthOptions.SlidingExpiration = false;).

I hope others find this useful. It took a lot of trial-and-error as reading to figure out what is going on under the hood.

.AddMicrosoftIdentityWebApp(authOptions =>
{
this.Configuration.Bind("AzureAD", authOptions);
authOptions.MaxAge = TimeSpan.FromDays(2);
}
, sessionOptions =>
{
// This appears to be obsolete. Don't use it because you get the following error | OptionsValidationException: Cookie.Expiration is ignored, use ExpireTimeSpan instead.
//sessionOptions.Cookie.Expiration = TimeSpan.FromMinutes(-1);

// Setting the MaxAge will convert Expiration Date on the cookie from 'Session' to an actual future date and will show the default expiration date that is 14 days in the
// future. However, note that the session cookie is different from the Authentication cookie, who's MaxAge is set in the AddMicrosoftIdentityWebApp extension method above
// with an expiration that is equal to the session cookie's expiration. Additionally, we set the SlidingExpiration to false. These three configurations are considered the
// safest and most secure. Otherwise, not setting the MaxAge while leaving the SlidingExpiration false results in CORS policy errors on the console after the session
// cookie has expired.
// Reference: https://brokul.dev/authentication-cookie-lifetime-and-sliding-expiration
sessionOptions.Cookie.MaxAge = cookieAuthOptions.ExpireTimeSpan;
sessionOptions.Cookie.Name = "SomeProjectName.Auth";
sessionOptions.ExpireTimeSpan = TimeSpan.FromHours(2);

// Keep this false and never change it to true. The problem with SlidingExpiration enabled is that the authentication cookie could be potentially re-issued infinitely.
// That's not a good security practice. If a hacker took control of the account, they could use it forever.
sessionOptions.SlidingExpiration = false;
});

ASP .NET Core Cookie Authentication expiration changes from timestamp to Session upon return

Short Answer

Set isPersistent: true when calling SignInManager.ExternalLoginSignInAsync.

Details

In the ASP.NET Core Web Application template, the AccountController.ExternalLoginCallback method contains this code:

_signInManager.ExternalLoginSignInAsync(
info.LoginProvider,
info.ProviderKey,
isPersistent: true); <------ set a persistent cookie.

If we set isPersistent: true when calling ExternalLoginSignInAsync , this startup configuration...

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Cookies.ApplicationCookie.CookieName = "MyApplicationCookie";
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(5);
options.Cookies.ApplicationCookie.SlidingExpiration = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();

...results in this application cookie...

MyApplicationCookie is persistent.

...which persists across browser sessions.

Set authentication token expiry in ASP.NET Core 6.0 MVC

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.



Related Topics



Leave a reply



Submit