-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bff with EF Server Side Sessions: Cannot insert duplicate key row in object 'Session.UserSessions' #1497
Comments
Do I understand correctly that you're running a BFF that has internal API endpoints scaled out across 4 instances? |
Yes, that is correct. So instead of one BFF-instance proxying to four separate instances, we simply have four BFF-instances. |
Can you please tell us more about how you've set this up?
|
Is there just one SPA for the BFF or are there multiple?There is just one SPA for the BFF, this is served by IIS separately (not served by the BFF). Both the SPA and all instances of the BFF are behind a load balancer (NGINX), with all calls to Can you share the startup code in program.cs for the BFF?We have quite a large builder.Services
.AddBff(options =>
{
options.EnableSessionCleanup = true;
options.ManagementBasePath = BffBasePath;
options.LicenseKey = identityConfiguration.DuendeLicenseKey;
})
.AddEntityFrameworkServerSideSessions(options => options
.UseSqlServer(connectionString, sqlServerOptions =>
{
sqlServerOptions.UseCompatibilityLevel(120);
sqlServerOptions.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
sqlServerOptions.MigrationsHistoryTable(MigrationTableName, SchemaName);
}))
.ConfigureEntityFrameworkSessionStoreOptions(options => options.DefaultSchema = SchemaName)
.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultSignOutScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.Cookie.Name = identityConfiguration.CookieName;
options.Cookie.SameSite = SameSiteMode.Strict;
options.ExpireTimeSpan = TimeSpan.FromMinutes(identityConfiguration.CookieExpirationMinutes);
options.Cookie.MaxAge = TimeSpan.FromMinutes(identityConfiguration.CookieExpirationMinutes);
options.SlidingExpiration = identityConfiguration.SlidingExpiration;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.HttpOnly = true;
})
.AddOpenIdConnect(options =>
{
options.CallbackPath = "/api/oidc/signin";
options.SignedOutCallbackPath = "/api/oidc/signout-callback";
options.Authority = identityConfiguration.Authority;
options.ClientId = identityConfiguration.ClientId;
options.ClientSecret = identityConfiguration.ClientSecret;
options.ResponseType = OpenIdConnectResponseType.Code;
options.ResponseMode = OpenIdConnectResponseMode.Query;
options.UsePkce = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.MapInboundClaims = true;
options.SaveTokens = true;
options.ClaimActions.Add(new MapAllClaimsAction());
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
options.Scope.Clear();
identityConfiguration.Scopes.ForEach(options.Scope.Add);
options.Events.OnRedirectToIdentityProvider = AddAcrValues;
options.Events.OnRemoteFailure = HandleRemoteFailure;
});
// ... more setup
var app = builder.Build();
// NGINX sets the X-Forwarded-... headers
app.UseForwardedHeaders();
// ... more setup
app
.UseAuthentication()
.UseMiddleware<ForumWebClaimsMiddleware>()
.UseBff()
.UseAuthorization();
app.MapBffManagementEndpoints();
app.MapReverseProxy(config => config.UseAntiforgeryCheck());
app.MapControllers().AsBffApiEndpoint();
app.Run(); Any customizations you have active that have to do with sessions?From the setup you can se that we use ServerSideSessions with EF-backed storage. Can't think of any particular customizations. If there is more info I can provide you with, please let me know 🙂 |
@RolandGuijt, is there any more information you need? |
Just to rule it out, can you please check the data protection settings against this document? If that doesn't lead to a solution, please share the data protection configuration code. |
@RolandGuijt our Data Protection should be solid: builder.Services
.AddDbContext<ForumWebApiKeysContext>(/* ...options... */)
.AddDataProtection(configure => configure.ApplicationDiscriminator = "...")
.SetApplicationName("...")
.PersistKeysToDbContext<ForumWebApiKeysContext>()
.ProtectKeysWithDpapiNG(); And as mentioned, the four instances work fine together, so I would be surprised to find out that data protection is involved. At our peak hours I would estimate we have somewhere around 700 unique users with one or more sessions (multiple devices). The error is only popping up a few times each day (~10). How is the edit: the |
The |
@RolandGuijt As our And in this case, both the Have you considered the suggestion in "Expected Behaviour" of the original post? |
We've done some further analysis and think that this might be a but in our library. If multiple tabs/windows/requests run the login flow when there is already an existing server side session it looks like we are not handling that correctly. We have to do some further investigations, so I'm leaving this open for now. |
Which version of Duende BFF are you using?
2.2.0
Which version of .NET are you using?
net8.0
Describe the bug
We have an API running four instances across two machines (two instances each). The API is set up with Bff and
.AddEntityFrameworkServerSideSessions()
and works fine. However, a few times each day (0 - 10) our logs show the following error:I'm speculating that this might be because a user has multiple tabs open, and when they open the browser for the first time after the cookie has expired, they all simultaneously log in, causing a race-condition of sorts.
To Reproduce
Unable to reproduce
Expected behavior
I'm not quite sure... I'm uncertain if this error is ignorable or not. I'm assuming the conflict comes from the data already being stored from the call that won the race to Db, if so, maybe something like:
Log output/exception with stacktrace
Already in description
The text was updated successfully, but these errors were encountered: