2

I'm having some issues passing the correct AntiForgertyToken when using AngularJS $http service in an ASP.NET MVC application.

I have tried the following:

  1. Setting HTTP Request headers with an httpInterceptor

    app.factory('httpInterceptorService', function ($q) {
        return {
            'request': function (config) {
                blockUI();
                config.headers['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Disables IE AJAX request caching
                config.headers['Cache-Control'] = 'no-cache';
                config.headers['Pragma'] = 'no-cache';
                config.headers['X-Requested-With'] = 'XMLHttpRequest';
                config.headers['__RequestVerificationToken'] = $('[name=__RequestVerificationToken]').val();
                return config;
            },
    
  2. Setting HTTP Request headers via a factory service

    app.factory('networkService', function ($http) {
        return {
            postDataAsAjax: function (url, params) {
                debugger;
                return $http({
                    method: 'POST',
                    url: url,
                    data: params,
                    headers: {
                        '__RequestVerificationToken': $('[name=__RequestVerificationToken]').val(),
                        'X-Requested-With': 'XMLHttpRequest'
                    }
                }).then(function (result) {
    

Both of these approaches are throwing AntiForgeryTokenException.

Is there any other method that I can achieve this?

EDIT (Added HTTP Request Info)

POST /WebApplication1/Home/Index HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 799
Cache-Control: no-cache
Pragma: no-cache
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
X-Requested-With: XMLHttpRequest
If-Modified-Since: Mon, 26 Jul 1997 05:00:00 GMT
__RequestVerificationToken: CKCARSoIug5mHnHmUT4ciSmf3pCk1YJkcwq3czo5snfEwTVPBUYLQj7z7w3KKDu001RYk7zuMZ1LEwwWB1tNpZR0agxJK1DjqjMDnQNewLKGCmExANXIJ-Du7lc0LEFw0
Referer: http://localhost/SSP-Working_SourceCode/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: __ngDebug=true; ASP.NET_SessionId=4kcpxz1oj0042ndw4aotx0jl; __RequestVerificationToken_L1NTUC1Xb3JraW5nX1NvdXJjZUNvZGU1=Q8FOz7jJHQHdes02AJvRGglFU_pcz5eqcnZY3QXg37z9k1LMYiPWq-kKbXlYCbAfK0IgLpCtpBax6w-rB1J_NBi7KzGyCuwLCHjKNREjMhQ1; .ASPXFORMSAUTH=CC35114F38FD17866FAF38A1FDC525263A0858EFECFB03AEEED7E9AF7FAA2995262A426D4AA50EB87C47969C3C191BC9B3D31BC67A831C099F286AD3013348B14659632BC54425E3D81C19CB382E175B2DA3755DDFE46D7A79810FB79EBE832D616A299C93CFDA2105576B922C6A1D111A23BB6F9594532C310A15AF2162785A

EDIT (Added custom anti forgery token attribute)

public class GlobalAntiForgeryTokenAttribute : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext authorizationContext)
    {
        var request = authorizationContext.HttpContext.Request;

        if (request.HttpMethod.ToUpper() != "POST")
        {
            return;
        }

        if (authorizationContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
            authorizationContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
        {
            return;
        }

        if (request.IsAjaxRequest())
        {
            var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
            var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;
            AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
        }
        else
        {
            new ValidateAntiForgeryTokenAttribute().OnAuthorization(authorizationContext);
        }
    }
}

EDIT (Added HTTP Response)

System.Web.Mvc.HttpAntiForgeryException: The required anti-forgery form field __RequestVerificationToken is not present.

4
  • Can you post what the HTTP request looks like? Commented Apr 29, 2016 at 14:55
  • @JohnMc Updated the post with HTTP request info. Commented Apr 29, 2016 at 15:38
  • Thanks. Can you confirm the exception is being thrown here: AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"])? If not,where? Commented Apr 29, 2016 at 15:46
  • @JohnMc Yes, that's where it is being thrown. Commented Apr 29, 2016 at 15:46

2 Answers 2

1

The problem is that the verification token is meant to be part of the form data but you're providing it in the header.

This post tells you how to build an attribute filter that validates the header instead.

Here is mine:

[AttributeUsage(AttributeTargets.Class)]
    public class ValidateAntiForgeryTokenOnAjax : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var request = filterContext.HttpContext.Request;

            //  Only validate POSTs
            if (request.HttpMethod == WebRequestMethods.Http.Post)
            {
                //  Ajax POSTs and normal form posts have to be treated differently when it comes
                //  to validating the AntiForgeryToken
                if (request.IsAjaxRequest())
                {
                    var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                    var cookieValue = antiForgeryCookie != null
                        ? antiForgeryCookie.Value
                        : null;

                    AntiForgery.Validate(cookieValue, request.Headers[AntiForgeryConfig.CookieName]);
                }
                else
                {
                    new ValidateAntiForgeryTokenAttribute()
                        .OnAuthorization(filterContext);
                }
            }
        }

I then configure angular like this:

var myApp = angular.module("myApp", ["ngRoute"])
    .run(function ($http) {
        $http.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
        $http.defaults.headers.post["__RequestVerificationToken"] = $("#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]").val();
    });

On my master layout page I declare this form:

<form id="__AjaxAntiForgeryForm" action="#" method="post">@Html.AntiForgeryToken()</form>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your response. We have a custom attribute which validates AJAX requests via the header. Please see updated post.
Here is my step-by-step approach on this issue. I am using angularJS, jquery, ASP.NET MVC 5 stackoverflow.com/a/57781976/2508781
0

For those who are facing a similar issue, the problem with our application was that the previous developer had also defined the default "ValidateAntiForgeryToken" attribute on the MVC controller action the requeset was POSTing to.

Once we removed [ValidationAntiForgeryToken] from the controller action, it started working.

We have a custom anti forgery token attribute which checks for the token in the header, but the default implementation of the MVC attribute only checks the request body, which was causing this to fail.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.