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
Build Visual Studio Project Through the Command Line
Using Profiles in Automapper to Map the Same Types with Different Logic
.Net (Dotnet) Wrappers for Opencv
Multi Processes Read&Write One File
Count Number of Bits in a 64-Bit (Long, Big) Integer
Quickest Way to Enumerate the Alphabet
"Movefile" Function in C# (Delete File After Reboot)
Check If List<T> Contains Any of Another List
How to Async Download Multiple Files Using Webclient, But One at a Time
Xml Parsing - Read a Simple Xml File and Retrieve Values
Iterating Through the Alphabet - C# A-Caz