How to Return 401 Instead of 302 in ASP.NET Core

How to return 401 instead of 302 in ASP.NET Core?

As of ASP.NET Core 2.x:

services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});

How do I return a 401 status instead of a 302 redirect after cookie has expired?

I changed my services.AddWsFederation() to the following and it appears to be working:

.AddWsFederation(options =>
{
options.Wtrealm = Configuration["Wtrealm"];
options.MetadataAddress = "http://example.com/metadata.xml";
options.SkipUnrecognizedRequests = true;
options.RequireHttpsMetadata = false;
options.UseTokenLifetime = false;
options.Events.OnRedirectToIdentityProvider = context =>
{
context.Response.StatusCode = 401;
context.HandleResponse();
return Task.CompletedTask;
};
})

ASP.NET Core 3.1 how to return 401 Unauthorized instead of Challenge with Azure AD B2C

For anyone (or me) reading in the future - I have solved the issue.
In ConfigureServices do:

        services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = AzureADB2CDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignOutScheme = AzureADB2CDefaults.AuthenticationScheme;
})
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
.AddCookie(options =>
{
options.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = context =>
{
if (context.Request.Path.StartsWithSegments("/api"))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
}
else
{
context.Response.Redirect(context.RedirectUri);
}

return Task.FromResult(0);
}
};
});

ASP.Net / ASP.NET Core Web API unauthorized requests returns 302 redirect response instead of 401

Finally found the solution.

The redirection happens with the Cookie Authentication module. By default its LoginPath property is set to /Account/Login. If it is set to PathString.Empty, it will keep the status code as 401-Unauthorized without changing it to 302-Found.

Change CookieAuthenticationOptions in Startup.cs as follows:

public void ConfigureServices(IServiceCollection services)
{
// Other configurations ...

services.Configure<CookieAuthenticationOptions>(o =>
{
o.LoginPath = PathString.Empty;
});

// ...
}

XML documentation of LoginPath property:

The LoginPath property informs the middleware that it should change an outgoing 401 Unauthorized status
code into a 302 redirection onto the given login path. The current url which generated the 401 is added
to the LoginPath as a query string parameter named by the ReturnUrlParameter. Once a request to the
LoginPath grants a new SignIn identity, the ReturnUrlParameter value is used to redirect the browser back
to the url which caused the original unauthorized status code.

If the LoginPath is null or empty, the middleware will not look for 401 Unauthorized status codes, and it will
not redirect automatically when a login occurs.


UPDATE: As @swdon pointed out, ASP.NET Core 2.x has a different way of doing this.

Here's the accepted answer from the link 1:

As of ASP.NET Core 2.x:

services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});

ASP.NET Core 3.1.1 Jwt redirects instead of returning http status 401 after migration from ASP.NET Core 2.2

That is because AddIdentity registers the default Cookie-based authentication schemes for the application itself, external sign-in (e.g. Facebook and Google), and 2FA . It will reset the default schema if you put services.AddIdentity<IdentityUser, IdentityRole>() below the AddJwtBearer config , to avoid this , you can put the identity config above the jwt bearer config :

services
.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders().AddDefaultUI();

services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
....

});

Use AddIdentityCore works because it won't registers the default Cookie-based authentication schemes , see AddIdentity vs AddIdentityCore for more details.

Identity Server 3 - 401 on Ajax Calls instead of 302

In your example the UseCookieAuthentication no longer controls this, instead the UseOpenIdConnectAuthentication does. This involves using the Notifications property and intercepting OpenID Connect authentication requests.

Try out the following for inspiration:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = IdentityConfig.Authority,
ClientId = IdentityConfig.SoftwareClientId,
Scope = "openid profile roles",
RedirectUri = IdentityConfig.RedirectUri,
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = notification =>
{
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.AuthenticationRequest)
{
if (IsAjaxRequest(notification.Request) && notification.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
{
notification.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
notification.HandleResponse();
return Task.FromResult(0);
}
}
return Task.FromResult(0);
}
}
});

IIS return 302 instead of 401

I found the solution for my problem here

Using a custom authorization attribute for redirect to the "AccessDenied" page



Related Topics



Leave a reply



Submit