Search code examples
jqueryasp.net-mvccsrf-protectionantiforgerytoken

__RequestVerificationToken is not present with Ajax POST


I'm using jQuery DataTales to request a POST URL from MVC5 and trying to add an anti-forgery token. I've added it to both the headers and also the request body, but still get a 500 error: "The required anti-forgery form field "__RequestVerificationToken" is not present."

The form:

<form id="my-units-form" action="@Url.Action("MyUnitsResults", "Provider")" class="form-horizontal criteria well well-sm">
    @Html.AntiForgeryToken()
    ....

The JavaScript:

$userDt = $('#users-table')
    .DataTable({
        serverSide: true,
        ordering: false,
        searching: true,
        ajax: {
            "url": url,
            "type": "POST",
            'contentType': 'application/json',
            "dataType": "json",
            headers: { '__RequestVerificationToken': $('form input[name=__RequestVerificationToken]').val() },
            data: function (d) {
                d.__RequestVerificationToken= $('form input[name=__RequestVerificationToken]').val();

                return JSON.stringify(d);
            }
        },

Headers

Payload


Solution

  • If your stringifying the data and using contentType: 'application/json, then add the token to the ajax headers only (it will not be read from the body).

    You then you need to create a custom FilterAttribute to read the value from the headers

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
    
            var httpContext = filterContext.HttpContext;
            var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
            AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
        }
    }
    

    and in your controller method, replace the [ValidateAntiForgeryToken] attribute with [ValidateHeaderAntiForgeryToken]