0

I'm using ASP.NET Core Identity (cookie authentication) with a YARP reverse proxy to protect another ASP.NET Core web API which also hosts an Angular SPA. All requests are sent to the reverse proxy which checks if the request is authenticated. If it is, the request is forwarded to the web API/SPA. If not, the page is redirected to a login page.

When the user is logged in and the SPA is loaded, requests to edit or create data (PUT/POST) are sent from the SPA to the web API and also pass through the reverse proxy. This works quite well until the end of the cookie lifetime is reached and a user wants to edit something. The reverseproxy wants to redirect to the login page, but then returns a 400 error and logs the following message:

Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter[1]
  Antiforgery token validation failed. Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.
  Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.
     at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)
     at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
     at Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)

I modified the AntiforgeryOptions as below:

builder.Services.Configure<AntiforgeryOptions>(options => 
{
  options.Cookie.Name = "XSRF-TOKEN";
  options.HeaderName = "X-XSRF-TOKEN";
  options.Cookie.HttpOnly = false; 
});

The Angular SPA has an HttpInterceptor which extracts the xsrf-token from the cookie and appends it to the headers of all outgoing requests. Verifying the tokens with browser dev tools, the token from the cookie is exactly the same as the one being added to the request headers. Therefore I don't understand why the validation of the token fails.

What am I overlooking here?

ChThy
  • 221
  • 1
  • 4
  • 12
  • If you keep the form open for longer than default timeout of 20 minutes, the ASP.NET token will have expired with the session. That's because it is also checked against the session cookie. (There's 2 cookies, 1 hidden field involved here...) You can set the session timeout in the application pool settings. – pcalkins Jul 15 '22 at 18:32
  • There are no hidden fields in de SPA as far as I can tell. Which token is 'AutoValidateAntiforgeryTokenAuthorizationFilter' expecting? I assume the token that was placed inside the cookie, but apparently this is not correct. – ChThy Jul 15 '22 at 20:48
  • It seems to be ASP.NET... not angular... so it's expecting 2 cookies, and 1 hidden field (in the body of the request or wherever user input would be...). AutoValidate is a sort of global requirement I think... any state changing verb (POST, PUT, etc...) will validate anti-forgery tokens: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.autovalidateantiforgerytokenattribute?view=aspnetcore-6.0 This could be a problem for login page if there is no session to tie to. (Does this error happen when re-logging in? or is it happening before the re-direct?) – pcalkins Jul 15 '22 at 21:05
  • 1
    I'm not familiar with Angular, but you might try the solution included in this page: https://www.dotnetcurry.com/aspnet/1343/aspnet-core-csrf-antiforgery-token (In the section titled: "CSRF tokens with Angular") OR just turn off the auto-validate setting if that's what's causing the issue. You can set anti-forgery per controller/action. – pcalkins Jul 15 '22 at 21:15
  • You may just want to check the redirect to make sure that's a GET. – pcalkins Jul 15 '22 at 21:28
  • 1
    The issue happens after redirecting when the login page tries to load. I read the dotnetcurry article and noticed that the configuration for working with Angular results in 2 antiforgery cookies. One for ASP.NET Core Identity (named .AspNetCore.Antiforgery) and the extra configured one appended to every result. Thanks a lot @pcalkins! – ChThy Jul 16 '22 at 05:04

0 Answers0