I'm building a single page application and experiencing an issue with anti-forgery tokens.
I know why the issue happens I just don't know how to fix it.
I get the error when the following happens:
- Non-logged-in user loads a dialog (with a generated anti-forgery token)
- User closes dialog
- User logs in
- User opens the same dialog
- User submits form in dialog
Anti forgery token is meant for user "" but the current user is "username"
The reason this happens is because my application is 100% single-page, and when a user successfully logs in through an ajax post to /Account/JsonLogin
, I simply switch out the current views with the "authenticated views" returned from the server but do not reload the page.
I know this is the reason because if I simple reload the page between steps 3 and 4, there is no error.
So it seems that @Html.AntiForgeryToken()
in the loaded form still returns a token for the old user until the page is reloaded.
How can I change @Html.AntiForgeryToken()
to return a token for the new, authenticated user?
I inject a new GenericalPrincipal
with a custom IIdentity
on every Application_AuthenticateRequest
so by the time @Html.AntiForgeryToken()
gets called HttpContext.Current.User.Identity
is, in fact my custom Identity with IsAuthenticated
property set to true and yet @Html.AntiForgeryToken
still seems to render a token for the old user unless I do a page reload.
You can test this by putting a break point on the first line of your Login (Get) action. Before adding the OutputCache directive the breakpoint would be hit on the first load, but after clicking the browser back button it wouldn’t. After adding the directive you should end up with the breakpoint being hit every time, so the AntiForgeryToken will be the corect one, not the empty one.
I had the same issue with a single-page ASP.NET MVC Core application. I resolved it by setting
HttpContext.User
in all controller actions which change the current identity claims (since MVC only does this for subsequent requests, as discussed here). I used a result filter instead of middleware to append the antiforgery cookies to my responses, which made sure that they were only generated after the MVC action had returned.Controller (NB. I'm managing users with ASP.NET Core Identity):
Result filter to append antiforgery cookies:
Startup.cs extract:
The message appears when you login when you are already authenticated.
This Helper does exactly the same thing as
[ValidateAntiForgeryToken]
attribute.Remove the
[ValidateAntiForgeryToken]
attribut from controller and place this helper in action methode.So when user is already authentificated, redirect to the home page or if not continue with the verification of the valid anti-forgery token after this verification.
It happens a lot of times with my application, so I decided to google for it!
I found a simple explanation about this error! The user are double-clicking the button for login! You can see another user talking about that on the link below:
MVC 4 provided anti-forgery token was meant for user "" but the current user is "user"
I hope it helps! =)
This is happening because the anti-forgery token embeds the username of the user as part of the encrypted token for better validation. When you first call the
@Html.AntiForgeryToken()
the user is not logged in so the token will have an empty string for the username, after the user logs in, if you do not replace the anti-forgery token it will not pass validation because the initial token was for anonymous user and now we have an authenticated user with a known username.You have a few options to solve this problem:
Just this time let your SPA do a full POST and when the page reloads it will have an anti-forgery token with the updated username embedded.
Have a partial view with just
@Html.AntiForgeryToken()
and right after logging in, do another AJAX request and replace your existing anti-forgery token with the response of the request.Just disable the identity check the anti-forgery validation performs. Add the following to your Application_Start method:
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
.To fix the error you need to place the
OutputCache
Data Annotation on the GetActionResult
of Login page as: