your middleware is checking the results before the antiforgery middleware runs. make it the last middleware, or check after calling Next();
note: I'm not sure controller continue processing the pipeline on an antiforgery validation error. so your middleware may not be called on error. if so, have it first and check after next call.
Customize antiforgery failure response
I want to customize the response received by the client when CSRF token validation fails. I was looking at ASP.NET Core's source code and found the middleware I think is supposed to handle CSRF token validation.
By looking at it I found that it sets an IAntiForgeryValidationFeature
, so I created a custom middleware to check if the feature is set and if it contains an error.
public class CustomAntiForgeryValidationResponseMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
IAntiforgeryValidationFeature? antiforgeryValidation = context.Features.Get<IAntiforgeryValidationFeature>();
if (antiforgeryValidation is not null && !antiforgeryValidation.IsValid)
{
context.Response.StatusCode = 403;
await context.Response.WriteAsJsonAsync(new ProblemDetails()
{
Title = "Forbidden",
Detail = "User is not allowed to perform this action",
Status = 403,
Extensions = new Dictionary<string, object?>()
{
{ "errors", new ApiError[] { new("Invalid or missing CSRF token") } }
}
});
}
await next(context);
}
}
I then added it to the request pipeline in Program.cs before app.UseAuthentication()
:
app.UseMiddleware<CustomAntiForgeryValidationResponseMiddleware>();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
However antiforgeryValidation
is always null even when the endpoint requires a CSRF token.
What am I doing wrong?
2 answers
Sort by: Most helpful
-
Bruce (SqlWork.com) 67,406 Reputation points
2024-11-21T17:10:04.0966667+00:00 -
iKingNinja 100 Reputation points
2024-11-21T21:39:46.24+00:00 Turns out the
AntiforgeryMiddleware
is not being invoked at all (probably because I am not using minimal APIs but rather MVC). I managed to fix this by creating a custom attribute and filter as the framework does and then globally registering the attribute.