I have a MVC website with some AngularJS components.
When I make a post request using angularjs, I always include the __RequestVerificationToken token from a hidden input on the page.
My problem is this:
User starts an anonymous session i.e not logged in.
The user logs in using angularjs component, which sends a post request. My MVC controller validates the credentials and the '__RequestVerificationToken'. Once the user is logged in, it returns a the new token.
The angularjs controller then takes the new token and updates the hidden input to be used for any future requests.
However the next request I make using angularjs fails the validation because the
var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName); (see below code sample) is still the old token from the anonymous session.
Although the "X-XSRF-Token" (see below code sample) is coming through as the new one.
How do I also update/renew the http cookie (tokenCookie) containing the token to the new one?
I have posted copy of my code below.
My action filter:
public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var headers = filterContext.HttpContext.Request.Headers;
var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName);
var tokenHeader = string.Empty;
if (headers.AllKeys.Contains("X-XSRF-Token"))
{
tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
}
AntiForgery.Validate(tokenCookie != null ? tokenCookie.Value : null, tokenHeader);
base.OnActionExecuting(filterContext);
}
}
My login controller:
[WebApiValidateAntiForgeryTokenAttribute]
[HttpPost]
public ActionResult login(string email, string password)
{
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password)) return new HttpUnauthorizedResult();
var rq = HttpContext.Request;
var r = validateLogin(email, password, true); // my login handling
if (r.Success)
{
Response.StatusCode = (int)HttpStatusCode.OK;
// within an action construct AJAX response and pass updated token to client
return Json(new
{
__RequestVerificationToken = UpdateRequestVerificationToken(Request)
});
}
else
{
return new HttpUnauthorizedResult();
}
}
/// <summary>
/// resets AntiForgery validation token and update a cookie
/// The new antiforgery cookie is set as the results and sent
/// back to client with Ajax
/// </summary>
/// <param name="Request">request from current context</param>
/// <returns>string - a form token to pass to AJAX response</returns>
private string UpdateRequestVerificationToken(HttpRequestBase Request)
{
string formToken;
string cookieToken;
const string __RequestVerificationToken = "__RequestVerificationToken";
AntiForgery.GetTokens(Request.Form[__RequestVerificationToken], out cookieToken, out formToken);
if (Request.Cookies.AllKeys.Contains(__RequestVerificationToken))
{
HttpCookie cookie = Request.Cookies[__RequestVerificationToken];
cookie.HttpOnly = true;
cookie.Name = __RequestVerificationToken;
cookie.Value = cookieToken;
Response.Cookies.Add(cookie);
}
return formToken;
}
My angularjs Login handling:
login(email, password) {
return new Promise((resolve, reject) => {
return this.AccountRequest.login(email, password)
.then(response => {
const newToken = response.data['__RequestVerificationToken'];
const oldTokenElement = angular.element('input[name="__RequestVerificationToken"]');
oldTokenElement.val(newToken); // confirmed the new token has been updated in the hidden element
resolve(this.refresh.bind(this));
});
})
}
Every time I make a post request using angularjs:
post(uri, queryParams = {}, data = null) {
this.$http.defaults.headers.common['X-XSRF-Token'] = angular.element('input[name="__RequestVerificationToken"]').attr('value');
this.$http.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; // Needed to ensure we get back http error instead of a webpage
const config = this.makeConfig('POST', uri, queryParams, data);
return this.$http(config);
}
makeConfig(method, uri, params = {}, data = null) {
return {
method,
data,
params,
url: uri.toString(),
};
}
__RequestVerificationToken. Could you clarify the reason for me? or point me to some documentation I could read up? any help is appreciated. thanks