I have created an ASP.NET 8 Core Web API and frontend is hosted on some other domain. I want to prevent CSRF attacks that is why I want to use antiforgery in my API. I am calling the API using AJAX and I am already using Jwt tokens – I guess that will not make any affect.
This is my setup – Program.cs
:
builder.Services.AddAntiforgery(options =>
{
options.HeaderName = "X-CSRF-TOKEN";
});
Controller method:
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class AdminController : HelperController
{
private readonly ErrorResponseService _errorResponseService;
private readonly IAntiforgery _antiforgery;
public AdminController(TruCastContext dbContext, IWebHostEnvironment hostEnvironment, TokenBlacklistService tokenBlacklistService, IConfiguration configuration, EmailService emailService, ErrorResponseService errorResponseService, IAntiforgery antiforgery, ILogger<AdminController> logger)
{
_dbContext = dbContext;
_errorResponseService = errorResponseService;
_antiforgery = antiforgery;
}
// POST: Get User and Channel Counts
[AllowAnonymous]
[HttpPost]
[Route("GetUserAndChannelCounts")]
public IActionResult GetUserAndChannelCounts()
{
try
{
var token = _antiforgery.GetTokens(HttpContext).RequestToken;
var tokenFromHeader = Request.Headers["X-CSRF-TOKEN"].ToString();
if (string.IsNullOrEmpty(tokenFromHeader))
{
return StatusCode(400, new { Message = "No anti-forgery token found in request header" });
}
// Perform token validation
if (!_antiforgery.IsRequestValidAsync(HttpContext).Result)
{
return StatusCode(400, new { Message = "Invalid anti-forgery token" });
}
var counts = new Count
{
UserTotalCount = _dbContext.UserDetails.Count(),
UserActiveCount = _dbContext.UserDetails.Count(u => u.IsActive),
UserInactiveCount = _dbContext.UserDetails.Count(u => !u.IsActive),
ChannelTotalCount = _dbContext.ChannelDetails.Count(),
ChannelActiveCount = _dbContext.ChannelDetails.Count(c => c.IsActive),
ChannelInactiveCount = _dbContext.ChannelDetails.Count(c => !c.IsActive)
};
// success response
var successResponse = new
{
Status = 200,
Message = "Count fetched successfully",
Details = counts
};
return Ok(successResponse);
}
catch (Exception ex)
{
var errorResponse = _errorResponseService.CreateErrorResponse(500, "Internal Server Error: " + ex.Message);
return StatusCode(500, errorResponse);
}
}
}
Dashboard.cshtml
:
<form id="dashboardform" asp-antiforgery="true">
@Html.AntiForgeryToken() <!-- this generates the anti-forgery token -->
</form>
Dashboard.js
:
$(document).ready(function () {
let connection = getAPIConnection();
let jwtToken = localStorage.getItem("jwtToken");
GetCount();
function GetCount() {
isLoading = true;
var url = connection + "api/Admin/Count";
// Get the Anti-Forgery token from the hidden input field
var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val();
console.log("Anti-Forgery Token: ", antiForgeryToken); // Check if the token is populated
$.ajax({
url: url,
method: 'POST',
headers: {
'Authorization': 'Bearer ' + jwtToken,
'X-CSRF-TOKEN': antiForgeryToken // Include Anti-Forgery token
},
success: function (response) {
if (response.Status === 200) {
console.log("Forgery Token: ", antiForgeryToken)
// Access the counts directly from the Details object
$('#tcCount').text(response.Details.ChannelTotalCount);
} else if (response.Status === 404) {
console.error("Counts not found");
} else {
console.error("Failed to retrieve channel details");
}
}
,
error: function (xhr, status, error) {
console.error("Error occurred: ", error);
}
});
}
});
I added antiforgery in program.cs
file and added manual antiforgery in my controller method to validate which is being sent through frontend header in correct format, but I get this error all the time:
Invalid Anti-Forgery Token
I am expecting that API should return the data instead of an error
Sayed Asad is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.