MVC3 AntiForgeryToken breaks on Ajax login MVC3 AntiForgeryToken breaks on Ajax login ajax ajax

MVC3 AntiForgeryToken breaks on Ajax login


You will need to clear and redo any existing form token you have upon login. This means your login code will have to either refresh the current page (kinda kills the ajax portion of it eh), your own token implementation, or you will need to refresh your token. It is possible to request a partial view, extract the token, and update your form. You could actually have a restful url which returns nothing but a token to an authenticated user. One may argue this is a security issue, but I don't believe so because it is simply an easier way to get a token rather than requesting any view -partial or otherwise.

You should be able to easily get the token instances to replace via:

var token = $('input[name=""__RequestVerificationToken""]');

EDIT After re-reading a few more times - I question

Why would you have a token on the form if the user isn't logged in. You allow the same form to be 'operated' while not logged in and logged in? Most sites on the net even in this case will redirect for a login. Am I understanding this correctly? If so, you may want to consider skipping the token here or use a second type of token for unauthenticated users. You I believe are saying an unauthenticated user can already submit something in the application - again if I understand this correctly - without being authenticated.


Ok, what I did was combine the answer from here: jQuery Ajax calls and the Html.AntiForgeryToken() with a partial. I'm using knockout but for those of you not familiar with it you should still be able to follow along pretty easily.

First my html:

<form id="__AjaxAntiForgeryForm" action="#" method="post">@{Html.RenderPartial("AntiForgeryToken");}</form><div id="loginTestView">    <button data-bind="visible: signedIn() == false,click: signIn">Sign In</button>    <button data-bind="visible: signedIn, click: signOut">Sign Out</button>    <form>        <button data-bind="click: testToken">Test Token</button>    </form></div>

The main difference being that instead of @Html.AntiForgeryToken() I have a AntiForgeryToken partial that contain @Html.AntiForgeryToken().

So to really clarify I now have a AntiForgeryToken.cshtml file with just:

@Html.AntiForgeryToken()

Now when you sign in/out you need to update the token so the javascript/jquery looks like:

$(document).ready(function () {    AddAntiForgeryToken = function (data) {        data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();        return data;    };    var viewmodel = function () {        var vm = this;        vm.signedIn = ko.observable(false);        vm.signIn = function () {            $.post('Home/SignIn', function () {                vm.signedIn(true);                $.get('Home/GetAuthToken', function (newToken) {                    $('#__AjaxAntiForgeryForm').html(newToken);                });            });        };        vm.signOut = function () {            $.post('Home/SignOut', function () {                vm.signedIn(false);                $.get('Home/GetAuthToken', function (newToken) {                    $('#__AjaxAntiForgeryForm').html(newToken);                });            });        };        vm.testToken = function () {            $.post('Home/TestToken', AddAntiForgeryToken({ stuff: 'stuff' }));        };    };    ko.applyBindings(new viewmodel(), $('#loginTestView')[0]);});

The main thing to pay attention to here is that the $.get needs to happen after the $.post to signIn/Out. This code could be cleaned up a bit, but that's the main take away. If you don't then since the requests are asynchronous the $.get could (and probably will) come back before you are actually signed in.

That should do it. I haven't run into any other times when the token is updated but it would just require just another call to update the partial.