Protip: Using Anti-Forgery Token with ASP.NET Web API on MVC 4 on AppHarbor

Published on Wednesday, April 24, 2013

I just ran into and solved this problem so I thought I'd share (I'll also be talking about this at my upcoming talk).

Anti-Forgery in MVC

In vanilla MVC, you'd do anti-forgery like this in your Razor view:

@Html.AntiForgeryToken()

Then in a controller (POST):

[ValidateAntiForgeryToken]
public ActionResult DoSomething() { }

Cool. But what about Web API? It uses a totally different pipeline and likely you're interacting with it via JQuery or other AJAX framework.

ValidateHttpAntiForgeryToken

Here are some references I used when trying to implement Anti-Forgery with Web API:

Here's the rub: the two SO posts above implement this quite differently than the MVC 4 SPA template and the last article referenced. Both approaches actually worked locally for me, but both failed once I deployed to AppHarbor.

The long and short of it is that I was using the HTTP header __RequestVerificationToken. This is a no-no and I'm sort of the dumb one here in that I should know not to use custom headers like that.

My friends, the proper way is to use the X-* convention, so the HTTP header in your AJAX requests become X-XSRF-Token instead.

Apparently, AppHarbor was stripping off the other header on AJAX POST. I was receiving an error about the given header could not be found.

The working solution is below:

The machineKey thing is also key to remember on a cloud host/web farm environment.

I hope that helps somebody out there.

Aside

In the last article referenced, the AntiForgery.GetTokens() didn't work for me on AH. I kept getting the error:

System.Web.Mvc.HttpAntiForgeryException (0x80004005): The required anti-forgery cookie "__RequestVerificationToken" is not present.

I didn't get far enough to see what actual cookies were present because I switched to the other method outlined in the two SO posts. I just thought you should know that it just didn't work. I believe it's because GetTokens does not create a new cookie if the cookieToken has a value where as using @Html.AntiForgeryToken() does. The source code makes that clear in the comments. Why it worked locally I have no idea and at this point, don't care!

About Kamran
Hi, I'm a professional full-stack developer who also loves to write, speak at conferences, work on side projects, contribute to open source, make games, and play them.
comments powered by Disqus
comments powered by Disqus