Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

400 Bad Request when POST-ing to Razor Page

My page has...

@page "{candidateId:int}"

... and

@Html.AntiForgeryToken()

Model has...

public void OnGet(int candidateId)
{

}

public void OnPost(int candidateId)
{

}

GET works fine. Here is my AJAX request..

$.ajax({
    type: "POST",
    url: "/Skills/" + candidateId,
    beforeSend: function (xhr) {

        xhr.setRequestHeader("XSRF-TOKEN",
            $('input:hidden[name="__RequestVerificationToken"]').val());
    },
    data: {

        name: 'hi mum'
    },

    success: function (response) {
    },
    failure: function (response) {

        alert(response);
    }
});

Browser receives useless error message... 400 Bad Request.

What am I missing?

like image 342
Ian Warburton Avatar asked Jan 22 '18 00:01

Ian Warburton


1 Answers

You are getting a 400 (Bad Request) response because the framework expects the RequestVerificationToken as part of the posted request.The framework uses this to prevent possible CSRF attacks. If your request does not have this information, the framework will return the 400 bad request. Your current code is not sending it.

Change the code to this

headers:
{
    "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val()
},

This will add a new item with key RequestVerificationToken to the request header and the framework should not throw a 400 response when the call is made. (assuming your view code generated the hidden input for the __RequestVerificationToken hidden input)

You can make the code more robust by injecting the IAntiforgery implementation to the view/page and using the GetAndStoreTokens method.

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
    return Xsrf.GetAndStoreTokens(Model.HttpContext).RequestToken;
}
}

and call this GetAntiXsrfRequestToken function to get the value in your javascript

headers:
{
    "RequestVerificationToken": '@GetAntiXsrfRequestToken()'
},

You also probably want to use the PageModel's CandidateId property to create the url. Something like this

url: "/Skills/@Model.CandidateId",

Also, you do need to call @Html.AntiForgeryToken() method explicitly to generate the token input. Having a form with post method with no action attribute value will generate the hidden input for you.

<form method="post">
   <!-- your inputs-->
</form>
like image 79
Shyju Avatar answered Oct 20 '22 02:10

Shyju