Question

How to Require Authentication for Each Browser Instance with ASP.NET Core?

Our application is in ASP.NET Core (.NET 6) using a MVC architecture with an authentication model that creates an "auth" cookie. After a user logs into the application with a Browser (Chrome), opening a new instance of the browser and navigating to the application allows them access without the logon page. We would like the application to require authentication for any browser instance. The following code is from a test application that I wrote to see if the issue was our application or not (test application has same behavior):

public const string APP_AUTH_SCHEME = "MyAuthScheme";

Program.cs:

// Services:
builder.Services.AddAuthentication(AuthModel.APP_AUTH_SCHEME)
        .AddCookie(AuthModel.APP_AUTH_SCHEME, options =>
        {
            options.LoginPath = new PathString("/account/logon");
            options.LogoutPath = new PathString("");
            options.Cookie.Name = AuthModel.APP_AUTH_SCHEME;
            options.Cookie.SameSite = SameSiteMode.Strict;
            options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        });
        builder.Services.AddHttpContextAccessor();


// Middleware Pipeline:
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

Note: I added the Cookie.SameSite and SecurePolicy, but they did not change the behavior.

Account Controller:

// async Logon Action:
            var claims = new[] {
                        new Claim(ClaimTypes.Name, model.UserName),
                        new Claim(ClaimTypes.Role, "User")
                    };

            var claimsIdentity = new ClaimsIdentity(claims, AuthModel.APP_AUTH_SCHEME);
            await _httpContextAccessor.HttpContext.SignInAsync(AuthModel.APP_AUTH_SCHEME,
                                                                new ClaimsPrincipal(claimsIdentity),
                                                                new AuthenticationProperties() { IsPersistent = false });

The Action of a Controller that requires authorization is marked with the [Authorize] tag. The above code works great when the user first accesses the application, but we need each browser instance to require authentication.

In advance, Thank you for your help!

 2  113  2
1 Jan 1970

Solution

 1

If the IsPersistent property only applies to closing the browser and reopening, is there a different, yet similar, property that applies to opening additional tabs?

2024-07-23
Heather Sockriter

Solution

 1

Cookies cannot be restricted to be within a single browser tab. They will always be shared between all sessions for a particular host. Since your authentication is based on cookies, you cannot achieve this goal by using cookie authentication.

There are mechanisms to store data on the client side that do not leak into different tabs. This however requires that your application does not utilize normal browser requests for which cookies are automatically included. This essentially means that you need to use a different authentication mechanism, e.g. bearer tokens which are sent as a different HTTP header, which also means that all requests to your server backend need to be made by custom JavaScript calls that include this authentication mechanism.

This approach would essentially turn your application into a single page application (SPA) because every “normal” navigation request to your server would need to be replaced by a client-side request that uses a different authentication mechanism.

If you want a traditional server-rendered application with normal browser navigation behavior, then you can only rely on cookies for safe storage and as means for authentication, which means that you cannot restrict the application to single tabs.

2024-07-23
poke