Hi,
The following describes an issue with an ASP.NET Core application using the Okta.AspNetCore library for OpenID Connect (OIDC) authentication. The login process works correctly, and users are successfully authenticated. However, when a user duplicates a tab after logging in, an issue arises.
Problem Description:
When a user is logged in and duplicates the browser tab, the duplicated tab does not retain the authenticated session. Instead, it seems to trigger an attempt to re-authenticate or displays an OIDC error message, preventing the user from accessing the application in the duplicated tab.
Duplicating the tab, gives me the below error :
https://sitename.com/signin-oidc
Expected Behavior:
When a tab is duplicated, the duplicated tab should inherit the session and authentication state from the original tab, allowing the user to continue using the application without needing to re-authenticate.
Relevant Code:
Here’s the code snippet used to configure Okta authentication in my Startup.cs (or equivalent):
using EPiServer.Security;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Okta.AspNetCore;
using System.Security.Claims;
using System.Text;
namespace xxx.EpiServer.Okta;
public static class OktaExtensions
{
///
/// Configures Okta Authentication.
///
/// The service collection.
/// The application configuration.
/// Indicates whether HTTPS redirection is enforced.
public static void ConfigureOkta(this IServiceCollection services, IConfiguration configuration, bool forceHttpsRedirect)
{
var scopes = configuration[“OktaScopes”]?
.Split(’ ', StringSplitOptions.RemoveEmptyEntries)
.Select(scope => scope.Trim())
.ToList();
services.AddAuthentication(options =>
{
options.DefaultScheme = "okta.auth";
options.DefaultAuthenticateScheme = "okta.auth";
options.DefaultSignInScheme = "okta.auth";
options.DefaultSignOutScheme = "okta.auth";
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie("okta.auth", options =>
{
options.Events.OnSignedIn = async ctx =>
{
if (ctx.Principal?.Identity is ClaimsIdentity claimsIdentity)
{
var synchronizingUserService = ctx.HttpContext.RequestServices.GetRequiredService<ISynchronizingUserService>();
await synchronizingUserService.SynchronizeAsync(claimsIdentity);
}
};
})
.AddOktaMvc(new OktaMvcOptions
{
OktaDomain = configuration["OktaDomain"],
ClientId = configuration["OktaClientId"],
ClientSecret = configuration["OktaClientSecret"],
AuthorizationServerId = configuration["OktaAuthorizationServerId"],
Scope = scopes,
CallbackPath = "/signin-oidc",
GetClaimsFromUserInfoEndpoint = true,
PostLogoutRedirectUri = "/",
OpenIdConnectEvents = new OpenIdConnectEvents
{
OnAuthenticationFailed = async context =>
{
context.HandleResponse();
await context.Response.BodyWriter.WriteAsync(Encoding.ASCII.GetBytes(context.Exception.Message));
},
OnTokenValidated = async ctx =>
{
if (ctx?.Principal?.Identity is ClaimsIdentity claimsIdentity)
{
var synchronizingUserService = ctx.HttpContext.RequestServices.GetRequiredService<ISynchronizingUserService>();
await synchronizingUserService.SynchronizeAsync(claimsIdentity);
}
if (!string.IsNullOrEmpty(ctx?.Properties?.RedirectUri))
{
var redirectUri = new Uri(ctx.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
if (redirectUri.IsAbsoluteUri)
{
ctx.Properties.RedirectUri = redirectUri.PathAndQuery;
}
}
},
OnRedirectToIdentityProvider = context =>
{
if (forceHttpsRedirect)
{
context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http:", "https:");
}
if (context.HttpContext.User.Identity?.IsAuthenticated == true && context.Response.StatusCode == 401)
{
context.Response.StatusCode = 403;
context.HandleResponse();
}
else if (context.Response.StatusCode == 401)
{
context.HandleResponse();
}
return Task.CompletedTask;
},
OnSignedOutCallbackRedirect = context =>
{
context.Response.Redirect("/");
context.HandleResponse();
return Task.CompletedTask;
}
}
});
// Configure TokenValidationParameters after AddOktaMvc
services.PostConfigureAll<OpenIdConnectOptions>(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
NameClaimType = "name",
RoleClaimType = "groups",
ValidateAudience = false
};
});
}
}
Environment:
- Application Framework: .net 8.0
- Okta Library Used:
Okta.AspNetCore(4.6.3) - Browser: (e.g., Chrome, Firefox, Safari)
Has anyone else encountered this issue with Okta.AspNetCore and duplicate tabs? Are there any known solutions, workarounds, or best practices for handling this scenario? Recommendations for configuring OpenIdConnectEvents or managing session state to address this are of particular interest.
Any guidance or suggestions would be greatly appreciated!