aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Cookie configuration mystery using `AddCookie` and `ConfigureApplicationCookie`

Open qui8t opened this issue 2 years ago • 4 comments

I am confused how to set the cookie options, it seems some options are effective only if set using AddCookie and some others if set using ConfigureApplicationCookie. For example,

  1. LoginPath would be effective only if set in AddCookie:
services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.LoginPath = "signin";
});

services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = "signin"; 
    // No effect; if the setting in `AddCookie` is removed, this will fall back to the default `Account/Login` option.
});
  1. ExpireTimeSpan would be effective only if set in ConfigureApplicationCookie:
services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromSeconds(30);
    // No effect; if the setting in `ConfigureApplicationCookie` is removed, this will fall back to the default timespan.
});

services.ConfigureApplicationCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromSeconds(30);
});

qui8t avatar Dec 28 '22 01:12 qui8t

You are mixing and matching things for generic cookie authentication (AddCookie) and things meant for asp.net identity (ConfigureApplicationCookie).

Which auth are you trying to use?

blowdart avatar Jan 03 '23 23:01 blowdart

Hi @qui8t. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

ghost avatar Jan 03 '23 23:01 ghost

I am trying to use Google authNZ with built-in asp.net identity, without leveraging any external library, so my config reads as the following

services
    .AddIdentity<AppUser, IdentityRole>()
    .AddEntityFrameworkStores<AccountDbContext>();

services.AddIdentityCore<AppUser>();

services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddJwtBearer()
    .AddCookie(options =>
    {
        options.LoginPath = "/account/login";
        options.Cookie.SameSite = SameSiteMode.Lax;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    })
    .AddGoogle(GoogleDefaults.AuthenticationScheme, options =>
    {
        options.ClientId = _clientId;
        options.ClientSecret = _clientSecret;
        options.UsePkce = true;
        options.ClaimActions.MapJsonKey(GoogleProfilePictureClaim, "picture", "url");
    });

services.ConfigureApplicationCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromDays(15);
    options.SlidingExpiration = true;
});

And add the following for the middleware setup.

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

app.UseCookiePolicy(
    new CookiePolicyOptions
    {
        MinimumSameSitePolicy = SameSiteMode.Lax,
        Secure = CookieSecurePolicy.Always
    });

qui8t avatar Jan 04 '23 00:01 qui8t

Ah got it. @HaoK how does this all hang together?

blowdart avatar Jan 04 '23 23:01 blowdart

@qui8t Underneath the covers all ConfigureApplicationCookie is doing is configuring the named cookie that identity sets as the default authentication scheme. Which is the "Identity.Application" cookie scheme. Your app is specifying your own cookie to use by default. Generally if you are not using the application cookie as the default scheme, you don't even to add it.

Basically you should be calling EITHER AddIdentity, or AddIdentityCore. If you call the former, that adds all of the authentication cookies for identity as well. If you call AddIdentityCore, you are responsible for wiring up the authentication part of things, which by default does this:

        services.AddAuthentication(o =>
        {
            o.DefaultScheme = IdentityConstants.ApplicationScheme;
            o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
        })
        .AddIdentityCookies(o => { });

HaoK avatar Jan 12 '23 22:01 HaoK

Thank you @HaoK for the elaboration. I removed services.AddIdentityCore<AppUser>();. If I am understanding it correct, I can setup the cookie in ConfigureApplicationCookie, so I changed my code as the following.

services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddJwtBearer()
    .AddCookie( /* config moved to ConfigureApplicationCookie */)
    .AddGoogle(GoogleDefaults.AuthenticationScheme, options =>
    {
        options.ClientId = _clientId;
        options.ClientSecret = _clientSecret;
        options.UsePkce = true;
        options.ClaimActions.MapJsonKey(GoogleProfilePictureClaim, "picture", "url");
    });

services.ConfigureApplicationCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromDays(15);
    options.SlidingExpiration = true;

    // moved here from AddCookie()
    options.LoginPath = "/account/login";
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

With this setup, at least options.LoginPath is not configured properly.

qui8t avatar Jan 13 '23 01:01 qui8t

What do you mean loginpath is not configured properly? Its not /account/login as you expect? This is likely due to AddIdentity stomping on it. If you want to configure the cookies yourself, a better alternative might be to remove the call to AddIdentity and keep AddIdentityCore, and don't use any of the built in identity cookies, then you have full control over the authentication/cookies and you won't have to deal with stomping on cookie settings.

HaoK avatar Jan 13 '23 21:01 HaoK

I want the user to be redirected to the "/account/login" page if the cookie has expired or they requested a protected resource while they are not authenticated yet. With the setup in my previous post, this does not happen. With the setup in my first post, this happens.

qui8t avatar Jan 13 '23 23:01 qui8t

I suggest not using the identity application cookies and configuring the cookie completely yourself rather than mixing and matching your own cookies with the identity cookies

HaoK avatar Jan 18 '23 05:01 HaoK

I'd love to avoid mixing, though I am trying to remark upon the fact that I can not implement the use-case I mentioned without mixing and matching them. It seems some functionality is available in one and some in the other. Please refer to my first post, and I am happy to elaborate if needed.

qui8t avatar Jan 18 '23 23:01 qui8t

services
  

As my understanding, you should remove .AddIdentity<AppUser, IdentityRole>() and replace with .AddIdentityCore<AppUser> instead, then try your login path again.

chuannguyen1208 avatar Feb 08 '23 13:02 chuannguyen1208

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

ghost avatar Feb 22 '23 19:02 ghost