3

The steps: The login page is opened in two different tabs.

  1. User A logs from Tab 1 (No issues)
  2. Without refreshing the tab 2, user B tries to log in. Redirects to 400 page.

(Exception: Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The provided antiforgery token was meant for a different claims-based user than the current user.)

Any solution to handle this?

  • Is there any demo to reproduce your issue? Are the tabs implemented by `Asp.Net Core view` or `Angular`? How did you configure `Antiforgery` in the tab? Did you place `Antiforgery` in the different tabs or the main page outside tabs? How did you configure `Antiforgery` in `Startup`? – Edward Oct 12 '18 at 02:30
  • Yes, I'm using Asp.Net Core views. And I have '@Html.AntiForgeryToken()' in my Login View. '[ValidateAntiForgeryToken]' attribute have added to my login action in the controller. Sorry, I do not have a live demo to show you... – Pabodha Wimalasuriya Oct 12 '18 at 04:31
  • How did you achieve two tabs with login? – Edward Oct 12 '18 at 07:58
  • 1. Get to the login page 2. Duplicate the tab (So now you have two tabs with login page) 3. From tab 1, user A logs in (No issues. login successful) 4. Now try login from tab 2 without refreshing it (by the same logged user or a different logged user.) (*** Exception comes and redirects to 400 page) – Pabodha Wimalasuriya Oct 12 '18 at 08:06
  • Share us complete steps to reproduce your issue. By default, User A login will refresh the page, how did you avoid refreshing? – Edward Oct 12 '18 at 08:13
  • These are the steps: (And I'm referring to a chrome browser) 1. Open chrome. A new tab opened. Go to login page 2. Now right click on the tab and click on duplicate. (This will open a new tab with same url: which means now you have two login pages) 3. Now from tab 1 , User A logs in. (here no issue) 4. Now go to your duplicated tab : It has the login form and User B logs in from it. (Here comes the exception from 4th step) – Pabodha Wimalasuriya Oct 12 '18 at 08:14

2 Answers2

9

I agree with @matt-shepherd that this is the correct behavior of the anti-forgery token validation. Tab B is in an expired state because the token in Tab B does not reflect that we have already logged in in Tab A the anti forgery token includes the username.

I am posting another answer here because in my app (.Net Core 2.2 using asp.net core identity and razor pages) System.Web.Helpers.AntiForgery.Validate() is not available.So I wasn't able to validate the token in the controller action as suggested by @matt-shepherd.

Instead I have created a filter inheriting from IAsyncAlwaysRunResultFilter thanks to Patrick Westerhoff's pull request that was merged to ASP.NET Core 2.2 code base :

public class RedirectAntiforgeryValidationFailedResultFilter : IAsyncAlwaysRunResultFilter
  {
    public Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
      if (context.Result is AntiforgeryValidationFailedResult)
      {
        context.Result = new RedirectToPageResult("/AntiForgeryError");
      }

      return next();
    }
  }

I have created a razor page named AntiForgeryError.

At last, I have configured my app to use the RedirectAntiforgeryValidationFailedResultFilter in Startup.cs:

services.AddMvc(options => options.Filters.Add<RedirectAntiforgeryValidationFailedResultFilter>())
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Yanal-Yves Fargialla
  • 1,257
  • 15
  • 16
  • This is also a good answer for .NET Core 2.2, thanks @Yanal-Yves – Matt Shepherd Oct 09 '19 at 05:00
  • I wanted to thank you so much for this answer. I ended up finding Patrick Westerhoff's PR first, but there are a lot of stale answers on this site for other questions for handling it as an exception which doesn't apply in Core 2.2+ world. – Brandon Barkley Jul 16 '20 at 17:02
3

This is the correct behaviour of the anti-forgery token validation. Tab B is essentially in an expired state. The only thing you can do here is to improve the way your system handles it.

I would recommend, for example, validating the token from within the controller action instead of using the attribute. To do this, just use this line as the first line of your Action: System.Web.Helpers.AntiForgery.Validate();. You can now catch any HttpAntiForgeryException thrown and respond to the user accordingly. e.g. telling the user that they're already logged in, or that they'll need to refresh the page, whichever is appropriate for your system.

Matt Shepherd
  • 782
  • 10
  • 21