I keep getting this message when trying to implement XSRF with Angular and .NET CORE: "Validation of the provided antiforgery token failed. The cookie token and the request token were swapped." I have the cookie and header names configured the same in both the Angular and API. Anyone have any ideas?
Process
Angular makes an initial call to this API method to retrieve cookie
[HttpGet("startSession")]
public async Task<IActionResult> StartSession()
{
AntiforgeryTokenSet tokens = this.antiForgery.GetAndStoreTokens(this.HttpContext);
this.HttpContext.Response.Cookies.Append(this.options.Value.Cookie.Name, tokens.RequestToken, new CookieOptions { HttpOnly = false });
return this.Ok(
new
{
Success = true
});
}
Angular then intercepts the next POST request and overrides default XSRF handling slightly since I need it to work for HTTPS URLs
// Override default Angular XSRF handling since it won't work for
absolute URLs and we have to prefix with "https://"
// Source:https://github.com/angular/angular/blob/master/packages/common/http/src/xsrf.ts
@Injectable()
export class HchbHttpXsrfInterceptor implements HttpInterceptor {
constructor(
private tokenService: HttpXsrfTokenExtractor) {}
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
const headerName = 'X-XSRF-TOKEN';
const lcUrl = req.url.toLowerCase();
// Skip both non-mutating requests.
// Non-mutating requests don't require a token
// anyway as the cookie set
// on our origin is not the same as the token expected by another origin.
if (req.method === 'GET' || req.method === 'HEAD' ) {
return next.handle(req);
}
const token = this.tokenService.getToken();
// Be careful not to overwrite an existing header of the same name.
if (token !== null && !req.headers.has(headerName)) {
req = req.clone({headers: req.headers.set(headerName, token)});
}
return next.handle(req);
}
}
I hit the same problem and I think I found the issue.
The options.Cookie.Name
in the AddAntiforgery
has to be different than the cookie you set manually using context.Response.Cookies.Append
.
Try to change the name of one of them and it will work. Right now you override the generated cookie that is using the options.Cookie.Name
name with the tokens.RequestToken
value.
You can notice the difference in the Developer Tools.
options.Cookie.Name
is marked as http only
(HttpOnly = true
)context.Response.Cookies.Append
is marked as HttpOnly = false
The second one is read from JS/Angular (you can read it in JS because the HttpOnly=false
and sent as a header in your ajax requests and validated against the default one that can't be read from JS)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With