I have an ASP.NET Core 3.1 application that uses cookie authentication and runs on a web farm. I want the application to share authenticated cookies between web servers. The issue is when I log in on Server A through the load balancer the next ajax request from Server B redirects back to the login page. (Status Code 302, Set-Cookie: .AspNet.SharedCookie=;)
If I log in directly to Server A and navigate pages - it works fine. So my suspicions are that Server B does not validate cookies generated by Server A. Here is configuration of DataProtection:
services.AddDataProtection(options =>
{
options.ApplicationDiscriminator = "MyApp";
})
.PersistKeysToFileSystem(new DirectoryInfo(GetKeysPath()))
.SetApplicationName("MyApp")
.SetDefaultKeyLifetime(TimeSpan.FromDays(365));
And authentication:
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/Login/Login";
options.LogoutPath = "/Login/Logout";
options.ReturnUrlParameter = "returnUrl";
options.Cookie.Name = ".AspNet.SharedCookie";
options.Cookie.Path = "/";
options.Cookie.IsEssential = true;
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
});
Does anybody know what I'm missing?
P.S.Initial issue I had with DataProtection, each server generated it's own keys so that other servers could not decrypt cookies and anti-forgery tokens. So I copied the same key file to each server and the issue disappeared.
Links I used:
I found the root cause of the issue, the problem was not in DataProtection, Authentication or Cookies. The problem was with Session, it used memory to store sessions so other servers (except which created) didn't know anything about the session. So I added storing session in database, like this one:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString =
_config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
and finally, my web farm is working fine.