locked
__requestverificationtoken error in javascript vue, MVC 5 RRS feed

  • Question

  • User955080112 posted

    I am attempting to use the ValidateAntiForgeryToken to prevent cross site forgery on my application. Keep getting the error

    the required anti-forgery form field __requestverificationtoken is not present

    Been seeing a lot of chatter on this but I have been unable to come up with a solution.

    The code:

    in my Index.cshtml, setting the AntiForgeryToken:

        @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
            {
                @Html.AntiForgeryToken()
            }

    in my ajax.utilities post method, setting the token:

        var post = function (options, callbacks) {
            // set default POST options
            options.type = "POST";
            options.dataType = options.dataType !== undefined ? options.dataType : "json";
            options.contentType = options.contentType !== undefined ? options.contentType : "application/json; charset=utf-8";
            var form = $('#__AjaxAntiForgeryForm');
            var token = $('input[name="__RequestVerificationToken"]', form).val();

           if (options.data !== undefined && options.data !== null && !isJson(options.data)) {
                options.data = $.extend({ __RequestVerificationToken: token }, options.data);
                options.data = JSON.stringify(options.data);     
         }

            return sendRequest(options, callbacks);
        };

    my jquery sets the header properly i.e. "X-Requested-With":

                if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
                        headers[ "X-Requested-With" ] = "XMLHttpRequest";
                }

    finally in my controller I designate the HttpPost and ValidateAntiForgery attributes:

     [HttpPost]
     [ValidateAntiForgeryToken]
     public  ActionResult CreateComposite(string name, int compositeTypeId, int componentTypeId, DateTime inceptionDate)

            {           
                return DispatchCommandWithJsonReturn(new CompositeCommands.CreateComposite(name, compositeTypeId, componentTypeId));
            }

    I still get the error the required anti-forgery form field __requestverificationtoken is not present

    Using MVC 5, I don't know if that is relevant

    Any ideas what is wrong?

    Monday, September 21, 2020 1:42 PM

Answers

  • User-821857111 posted

    The ValidateAntiForgery attribute expects the token to be present as a form field. You are sending the post data as JSON so it's sent as a string in the request body, not as name/value pairs. Therefore the token value cannot be found by the model binder.

    You could send the request without using JSON, or you could send two parameters - the token value and the rest as JSON:

    options.data: { __RequestVerificationToken: token , json: JSON.stringify(options.data)};

    There are some other suggestions here: https://stackoverflow.com/questions/2906754/how-can-i-supply-an-antiforgerytoken-when-posting-json-data-using-ajax

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, September 22, 2020 6:18 AM
  • User-1330468790 posted

    Hi mndotnetdev,

     

    There is another option that you could manually post the data as a form within the header to be "headers: { 'Content-Type': 'application/x-www-form-urlencoded' }" and  'contentType : "application/x-www-form-urlencoded; charset=utf-8"'  

     

    You could refer to below codes to see how it works.

    cshtml:

    @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
    {
        @Html.AntiForgeryToken()
    
        @Html.TextBoxFor(model => model.name)
        @Html.TextBoxFor(model => model.componentTypeId)
        @Html.TextBoxFor(model => model.compositeTypeId)
        @Html.TextBoxFor(model => model.inceptionDate)
    
    
        <input type="submit" value="Submit" />
    
    }
    
    <input type="button" onclick="sendPost()" value="Send Post" />
    
    
    
    @section scripts {
        <script>
            var post = function (options, callbacks) {
                // set default POST options
                options.type = "POST";
                options.dataType = options.dataType !== undefined ? options.dataType : "json";
                options.contentType = options.contentType !== undefined ? options.contentType : "application/x-www-form-urlencoded; charset=utf-8";
                
                return sendRequest(options, callbacks);
            };
    
            var sendRequest = function (options, callbacks) {
                console.log(options);
                $.ajax(options).done(function (data) { callbacks(data)});
            }
    
            function sendPost() {
                
                var form = $('#__AjaxAntiForgeryForm');
                post({
                    url: "CreateComposite",
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                   
                    data: form.serialize()
                }, function (data) {
                        
                        alert(JSON.stringify(data));
    
                })
            }
    
            function isJson(str) {
                try {
                    JSON.parse(str);
                } catch (e) {
                    return false;
                }
                return true;
            }
    
        </script>
    
    }

    Controller:

     [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult CreateComposite(string name, int compositeTypeId, int componentTypeId, DateTime inceptionDate)
    
            {
                return Json(new { name, compositeTypeId, componentTypeId, inceptionDate });
            }

    model:

    public class AboutViewModel
        {
            public string name { get; set; }
    
            public int compositeTypeId { get; set; }
            public int componentTypeId { get; set; }
            public DateTime inceptionDate { get; set; }
        }

    Demo:

     

    Hope this can help you.

    Best regards,

    Sean
     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, September 22, 2020 8:02 AM

All replies

  • User-821857111 posted

    The ValidateAntiForgery attribute expects the token to be present as a form field. You are sending the post data as JSON so it's sent as a string in the request body, not as name/value pairs. Therefore the token value cannot be found by the model binder.

    You could send the request without using JSON, or you could send two parameters - the token value and the rest as JSON:

    options.data: { __RequestVerificationToken: token , json: JSON.stringify(options.data)};

    There are some other suggestions here: https://stackoverflow.com/questions/2906754/how-can-i-supply-an-antiforgerytoken-when-posting-json-data-using-ajax

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, September 22, 2020 6:18 AM
  • User-1330468790 posted

    Hi mndotnetdev,

     

    There is another option that you could manually post the data as a form within the header to be "headers: { 'Content-Type': 'application/x-www-form-urlencoded' }" and  'contentType : "application/x-www-form-urlencoded; charset=utf-8"'  

     

    You could refer to below codes to see how it works.

    cshtml:

    @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
    {
        @Html.AntiForgeryToken()
    
        @Html.TextBoxFor(model => model.name)
        @Html.TextBoxFor(model => model.componentTypeId)
        @Html.TextBoxFor(model => model.compositeTypeId)
        @Html.TextBoxFor(model => model.inceptionDate)
    
    
        <input type="submit" value="Submit" />
    
    }
    
    <input type="button" onclick="sendPost()" value="Send Post" />
    
    
    
    @section scripts {
        <script>
            var post = function (options, callbacks) {
                // set default POST options
                options.type = "POST";
                options.dataType = options.dataType !== undefined ? options.dataType : "json";
                options.contentType = options.contentType !== undefined ? options.contentType : "application/x-www-form-urlencoded; charset=utf-8";
                
                return sendRequest(options, callbacks);
            };
    
            var sendRequest = function (options, callbacks) {
                console.log(options);
                $.ajax(options).done(function (data) { callbacks(data)});
            }
    
            function sendPost() {
                
                var form = $('#__AjaxAntiForgeryForm');
                post({
                    url: "CreateComposite",
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                   
                    data: form.serialize()
                }, function (data) {
                        
                        alert(JSON.stringify(data));
    
                })
            }
    
            function isJson(str) {
                try {
                    JSON.parse(str);
                } catch (e) {
                    return false;
                }
                return true;
            }
    
        </script>
    
    }

    Controller:

     [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult CreateComposite(string name, int compositeTypeId, int componentTypeId, DateTime inceptionDate)
    
            {
                return Json(new { name, compositeTypeId, componentTypeId, inceptionDate });
            }

    model:

    public class AboutViewModel
        {
            public string name { get; set; }
    
            public int compositeTypeId { get; set; }
            public int componentTypeId { get; set; }
            public DateTime inceptionDate { get; set; }
        }

    Demo:

     

    Hope this can help you.

    Best regards,

    Sean
     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, September 22, 2020 8:02 AM