Troubleshooting anti-forgery token problems
You should prevent double form submission. I prevent this type of issue using code like this:
$('#loginForm').on('submit',function(e){
var $form = $(this);
if (!$form.data('submitted') && $form.valid()) {
// mark it so that the next submit can be ignored
$form.data('submitted', true);
return;
}
// form is invalid or previously submitted - skip submit
e.preventDefault();
});
or
$('#loginForm').submit(function () {
$(this).find(':submit').attr('disabled', 'disabled');
});
After help from Adam, I get the MVC source added to my project, and was able to see there are many cases that result in the same error.
Here is the method used to validate the anti forgery token:
public void Validate(HttpContextBase context, string salt) {
Debug.Assert(context != null);
string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);
HttpCookie cookie = context.Request.Cookies[cookieName];
if (cookie == null || String.IsNullOrEmpty(cookie.Value)) {
// error: cookie token is missing
throw CreateValidationException();
}
AntiForgeryData cookieToken = Serializer.Deserialize(cookie.Value);
string formValue = context.Request.Form[fieldName];
if (String.IsNullOrEmpty(formValue)) {
// error: form token is missing
throw CreateValidationException();
}
AntiForgeryData formToken = Serializer.Deserialize(formValue);
if (!String.Equals(cookieToken.Value, formToken.Value, StringComparison.Ordinal)) {
// error: form token does not match cookie token
throw CreateValidationException();
}
string currentUsername = AntiForgeryData.GetUsername(context.User);
if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) {
// error: form token is not valid for this user
// (don't care about cookie token)
throw CreateValidationException();
}
if (!String.Equals(salt ?? String.Empty, formToken.Salt, StringComparison.Ordinal)) {
// error: custom validation failed
throw CreateValidationException();
}
}
My problem was that condition where it compares the Identity user name with the form token's user name. In my case, I didn't have the user name set (one was null, the other was an empty string).
While I doubt many will run into this same scenario, hopefully others will find it useful seeing the underlying conditions that are being checked.
I don't know if you mean you are able to get the error on demand - or you're seeing it in your logs but in any case here's a way to guarantee an antiforgery token error.
Wait for it...
- Make sure you're logged out, then enter your login
- Double click on the login button
- You'll get :
The provided anti-forgery token was meant for user "", but the current user is "[email protected]".
(For now I'm going to assume that this exact error message changed in MVC4 and that this is essentially the same message you're getting).
There's a lot of people out there that still double click on everything - this is bad! I just figured this out after just waking up so how this got through testing I really don't know. You don't even have to double click - I've got this error myself when I click a second time if the button is unresponsive.
I just removed the validation attribute. My site is always SSL and I'm not overly concerned about the risk. I just need it to work right now. Another solution would be disabling the button with javascript.
This can be duplicated on the MVC4 initial install template.
AntiForgeryToken also checks your logged in user credentials haven't changed – these are also encrypted in the cookie. You can turn this off by setting AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
in the global.asax.cs file.