Why is a .net core controller Post method not accepting the anti forgery token? - .net-core

I’m trying to do a POST using an API call for a form using a reactive framework (Vue 3 in my case). I’m using .net 6.0. It is not accepting the anti forgery request token. I’m putting it in the body of the request like it is for a traditional form submit.
The call in Javascript:
var token = $('input[name="__RequestVerificationToken"]').val();
var url = '/api/ShareAllocations';
$.ajax({
type: "POST",
url: url,
data: { fa: fa, '__RequestVerificationToken': token },
success: function (result) {
console.log(result)
},
complete: function (e) { },
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.responseText);
}
});
In Fiddler, the textView of the input looks like this:
Fa= … (Json data)
__RequestVerificationToken=CfDJ8BSiPpdXlmRFvbl4LFJ0x7iHfmWBSdPblTwBjlLUq-We2oD60dKqBCYx4dUwXG5Gxprtl3lW2zzs4K8_iBf8eu0RQqOM928ANv1-16rcqizvYhUDFC5iaDo97wpqCsdFFxlmhiRaHW1zxhmEcwpYMrpZWBnzUbjGkTa-qUSs5GfuT2MwJGEWWYqyz7D95RRJVA
The API call returns a 200, but then the web page shows a 400 Bad Request.
From Fiddler:
143 200 HTTPS localhost:7164 /api/ShareAllocations
144 400 HTTPS localhost:7164 /FarmAllocation/Manage
For comparison purposes, I’m showing the body of a submit in .net core. The key value pair for the anti forgery token looks the same to me.
SENIOR_LIVING_FACILITIES.FACILITY_ID=0&SENIOR_LIVING_FACILITIES.FACILITY_NAME=n&SENIOR_LIVING_FACILITIES.ADDRESS=&SENIOR_LIVING_FACILITIES.CITY=&SENIOR_LIVING_FACILITIES.STATE=ME&SENIOR_LIVING_FACILITIES.ZIP=&SENIOR_LIVING_FACILITIES.CONTACT_NAME=&SENIOR_LIVING_FACILITIES.CONTACT_ROLE=&SENIOR_LIVING_FACILITIES.PHONE=&SENIOR_LIVING_FACILITIES.EMAIL=&__RequestVerificationToken=CfDJ8BSiPpdXlmRFvbl4LFJ0x7iHfmWBSdPblTwBjlLUq-We2oD60dKqBCYx4dUwXG5Gxprtl3lW2zzs4K8_iBf8eu0RQqOM928ANv1-16rcqizvYhUDFC5iaDo97wpqCsdFFxlmhiRaHW1zxhmEcwpYMrpZWBnzUbjGkTa-qUSs5GfuT2MwJGEWWYqyz7D95RRJVA

It turns out the post was working fine. Passing the token in the body of the message works fine. I had a side effect because of a submit button so the 400 bad request was not pertinent.

Related

Where do ajax headers go when making a server call?

I am new to the web developer side and am trying to make sense of how AJAX headers work. We use .NET Framework MVC project with some methods on the controller that are called by our views to get some data.
Example of our view ajax call to the server:
jQuery.ajax({
type: "POST",
data: { "ElementPath": ElementPath },
dataType: "json",
headers: {
'VerificationToken': forgeryId
},
url: "" + BasePath + "/Home/GetAttributes",
});
The GetAttributes method on the server accepts a string as a parameter and returns a string of JSON objects. When I put a breakpoint on the method, the only thing I see in the string parameter is the contents of ElementPath, and nothing to do with headers. In my mind the server method would also have the contents of forgeryId. So what exactly is using the headers and how?

How to call server api decorated with ValidateAntiForgeryToken using Httpclientfactory Typed clients?

I am trying to incorporate a Edit Form page using GetAsync and PostAsync using typed httpclient. Everything works except my code doesn't call API actions with ValidateAntiForgeryToken. Most of the examples online do not address httpcontent used by httpclientfactory and instead use httpresponse. I am aware that the antiforgery token is missing on my request. How do I attach it to the request header? How do I retrieve it from the view? I want to use as less Javascript as possible. Here's a snippet of my Post request service.
Edit: For what it's worth, my api is dot net core and client is dot net core mvc.
var response = await _httpclient.PostAsync("api/edit/" + id, httpcontent);
response.EnsureSuccessStatusCode(); ```
In the MVC Edit view page, it will use a hidden file (named __RequestVerificationToken) to store the ValidateAntiForgeryToken, you can use F12 developer tools to check it.
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
After modifying the data, you could use JQuery to get the updated data, then use JQuery ajax to call the API method with the ValidateAntiForgeryToken. You can refer the sample code in my reply:
if we customize antiforgery options in Startup.ConfigureServices, such as: custom the Header Name for the RequestVerificationToken.
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN"); //configure the antiforgery service to look for the X-CSRF-TOKEN header. To prevent the cross-site request forgery.
Then, we could use the following script:
$.ajax({
type: "POST",
url: "/Survey/Create",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: { "CategoryName": $("#CategoryName").val(), "CategoryID": $("#CategoryID").val() },
success: function (response) {
alert(response);
},
failure: function (response) {
alert(response.responseText);
},
error: function (response) {
alert(response.responseText);
}
});
Besides, you can also refer Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core.

jQuery Ajax Stop is not invoked (No error; 200 OK)

I have a working ASP.Net 2.0 code in my development server that uses jQuery Ajax. The result of the ajax call is used to load dropdown values.
But when this code is deployed to a new DMZ server, the result is not getting populated in dropdown – though I am getting 200 OK as response. One obvious thing is that the Type is different in the response. It is expected as application/json but coming as text/plain.
I have success call back and error callback codes. Along with this I have handlers for ajax start and stop. But none of these events are getting fired. What is the reason error/stop handlers are not getting fired? How can we make it work?
Note: The behavior is same in both IE and Chrome.
Update
Also observed that there is an error logged in console, as shown below. Is it related to the "Type"? How can we address this?
Note: Also note that the Content-Length is 0 in the response headers shown below.
Success Callback
jQuery
function loadASN()
{
var receiveScanParameter = getContainerParameters();
// console.log(receiveScanParameter);
$.ajax({
type: "POST",
url: "rcvScanTXAdd.aspx/GetASNForPlant",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify({ receiveScanParameter: receiveScanParameter }),
success: successPopulateASN,
error: errorFunction
});
}
Global jQuery Code
//Global Ajax Error handling Function
function errorFunction(xhr, status, error)
{
if(xhr == 'undefined' || xhr == undefined)
{
alert('xhr undefined');
}
alert(status);
alert(error);
}
$(document).ready(function ()
{
//Ajax Start
$('body').ajaxStart(function()
{
//Change cursor to waiting
$(this).css({'cursor':'wait'})
});
//Ajax End
$('body').ajaxStop(function() {
//Reset the cursor
$(this).css({'cursor':'default'})
});
});
Screenshots
I figured it out.
Step 1: Observed that there is an error logged in browser’s console (saying result is null). [This screenshot is updated in the question]
Step 2: Observed that the content length of the response is zero. Also observed that there is a gzip compression happened on the response (by reading the response headers).
Step 3: Analyzed the server's web.config. It was uisng a C# httpModule for compression. In that httpModule added bypassing logic for json. [I don’t want json to be compressed with this custom module. Later I will consider adding compression to JSON when I use IIS for compression instead of custom module]. Following is the C# code segment for by-passing JSON compression
request.ContentType.ToLower(CultureInfo.InvariantCulture).StartsWith("application/json")
WHen in doubt, read the API docs:
As of jQuery 1.8, the .ajaxStop() method should only be attached to document.
http://api.jquery.com/ajaxStop/
Same note can be found in $.ajaxStart docs

How does Angular know there was an error on an $http request?

How does the $http function of Angular "know" the response was an error in an ASP.NET request? I'm looking at the response headers but don't see anything that looks relevant.
I have this service in Angular:
service.getStuff = function () {
return $http({
method: 'GET',
url: './GetJsonData.aspx?RequestType=Stuff'
//That asp.net page returns json on success, but a regular
//asp.net error page on failure. I know there's better ways,
//but ignore that, that's not the question here.
});
}
and I use it like this:
$scope.reloadData = function () {
MyService.getStuff().success(function (response) {
alert("good");
})
.error(function (response) {
alert("bad");
});
};
That asp.net page is (correctly) throwing an exception on bad input and angular is (correctly) recognizing it as an error. But I can't figure out it knows there was an error. Is there some header that's it looking for? In the success case I receive json and in the failure case i receieve HTML, so as a human; but the angular code doesn't know that. So how is it recognizing this was an error?
It uses the HTTP status codes. This is standard behavior for restful clients and services.

Ajax call to ASP.NEt Web Api method. Parser error when it is done from HTTPS page

$.ajax({
url: "api/basket",
type: "GET",
dataType: "json",
error: function (request, status, error) {
alert(request.responseText);
},
success: function (data) {
Process(data);
}
});
I use ASP.NEN Web forms, .Net Framework 4.0, there is an ajax call above which I make . And when it is done from normal HTTP page it gives me data, But if I make this call being on HTTPS page it returns parserror "Unexpected token <"
What is wrong?
Your ajax request isn't returning JSON, it is returning HTML or XML. Thus, when jQuery attempts to parse the response, the first character is sees is < and it throws the parse error.
Use a debugging tool such as fiddler to see exactly what your request returns.

Resources