ASP.NET Core 2.0 disable automatic challenge

After upgrading my ASP.NET Core project to 2.0, attempts to access protected endpoints no longer returns 401, but redirects to an (non-existing) endpoint in an attempt to let the user authenticate.

The desired behaviour is for the application simply to return a 401. Previously I would set AutomaticChallenge = false when configuring authentication, but according to this article the setting is no longer relevant (in fact it doesn't exist anymore).

My authentication is configured like this:

Startup.cs.ConfigureServices():

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(o =>
                {
                    o.Cookie.Name = options.CookieName;
                    o.Cookie.Domain = options.CookieDomain;
                    o.SlidingExpiration = true;
                    o.ExpireTimeSpan = options.CookieLifetime;
                    o.TicketDataFormat = ticketFormat;
                    o.CookieManager = new CustomChunkingCookieManager();
                });

Configure():

app.UseAuthentication();

How can I disable automatic challenge, so that the application returns 401 when the user is not authenticated?


As pointed out by some of the other answers, there is no longer a setting to turn off automatic challenge with cookie authentication. The solution is to override OnRedirectToLogin:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
         {                 
             options.Events.OnRedirectToLogin = context =>
             {
                 context.Response.Headers["Location"] = context.RedirectUri;
                 context.Response.StatusCode = 401;
                 return Task.CompletedTask;
             };
         });

This may change in the future: https://github.com/aspnet/Security/issues/1394


After some research, I found we can deal with this problem though the bellow approach:

We can add two Authentication scheme both Identity and JWT; and use Identity scheme for authentication and use JWT schema for challenge, JWT will not redirect to any login route while challenge.

services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>();

services.AddAuthentication((cfg =>
{
    cfg.DefaultScheme = IdentityConstants.ApplicationScheme;
    cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})).AddJwtBearer();

Similiar to @Serverin, setting the OnRedirectToLogin of the Application Cookie worked, but must be done in statement following services.AddIdentity in Startup.cs:ConfigureServices:

services.ConfigureApplicationCookie(options => {
  options.Events.OnRedirectToLogin = context => {
    context.Response.Headers["Location"] = context.RedirectUri;
    context.Response.StatusCode = 401;
    return Task.CompletedTask;
  };
});

According to this article:

In 1.x, the AutomaticAuthenticate and AutomaticChallenge properties were intended to be set on a single authentication scheme. There was no good way to enforce this.

In 2.0, these two properties have been removed as flags on the individual AuthenticationOptions instance and have moved into the base AuthenticationOptions class. The properties can be configured in the AddAuthentication method call within the ConfigureServices method of Startup.cs

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

Alternatively, use an overloaded version of the AddAuthentication method to set more than one property. In the following overloaded method example, the default scheme is set to CookieAuthenticationDefaults.AuthenticationScheme. The authentication scheme may alternatively be specified within your individual [Authorize] attributes or authorization policies.

services.AddAuthentication(options => {
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});

Define a default scheme in 2.0 if one of the following conditions is true:

  • You want the user to be automatically signed in
  • You use the [Authorize] attribute or authorization policies without specifying schemes

An exception to this rule is the AddIdentity method. This method adds cookies for you and sets the default authenticate and challenge schemes to the application cookie IdentityConstants.ApplicationScheme. Additionally, it sets the default sign-in scheme to the external cookie IdentityConstants.ExternalScheme.

Hope this help you.


This is the source code of CookieAuthenticationEvents.OnRedirectToLogin :

public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context =>
{
    if (IsAjaxRequest(context.Request))
    {
        context.Response.Headers["Location"] = context.RedirectUri;
        context.Response.StatusCode = 401;
    }
    else
    {
        context.Response.Redirect(context.RedirectUri);
    }
    return Task.CompletedTask;
};

You can add "X-Requested-With: XMLHttpRequest" Header to the request while making API calls from your client.