Open Closed

InvalidOperationException: "This form is being accessed with an invalid anti-forgery token" after implementing route-based multi-tenancy in Blazor + AuthServer #10815


User avatar
0
alex.oommen created

Hi ABP Team, This is a continuation of the following support thread: https://abp.io/support/questions/10739/Multi-tenant-authentication-provider-selection-based-on-route-parameter# As suggested, I implemented tenant resolution from the route based on the following ABP Community article in both the Blazor project and the AuthServer: https://abp.io/community/articles/resolving-tenant-from-route-in-abp-framework-ah7oru97#gsc.tab=0 The tenant route resolution has been implemented in both the Blazor application and the AuthServer using the approach described in the blog above.

Issue

After implementing this, authentication starts correctly, but when the authentication flow returns to the Blazor application, I receive the following exception: InvalidOperationException: This form is being accessed with an invalid anti-forgery token. Validate the IAntiforgeryValidationFeature on the request before reading from the form. The exception occurs during the OIDC callback to: /signin-oidc

Authentication Flow

  • https://localhost:44314/Tenant1: Here tenant gets resolved and when I click login, It navigates to
  • https://localhost:44314/Account/Login and then
  • https://localhost:44322/Account/Login?ReturnUrl..................
  • After Signing in it navigates to https://localhost:44314/signin-oidc, at this point the exception occurs as mentioned above.

Questions

  • Is there any special consideration when using the route-based tenant resolution approach together with the OpenID Connect callback (/signin-oidc)?
  • Is there a recommended way to prevent the route-based tenant middleware from interfering with the OIDC authentication flow?
  • Is there any known issue or additional configuration required to avoid the anti-forgery validation exception in this scenario?

Any guidance or recommended approach would be greatly appreciated. Thank you!

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

2 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • POST /signin-oidc is an OpenID Connect callback endpoint and must not be affected by your “tenant-from-route” Path/PathBase rewriting middleware/contributor logic.
    • With the route-based approach from the community article, the middleware often rewrites:
      • Request.Path (e.g., from /Tenant1/signin-oidc to /signin-oidc) and/or
      • Request.PathBase (e.g., to /Tenant1) which is fine for normal pages, but it can break OIDC’s correlation/nonce/state validation flow. That frequently manifests as antiforgery/form validation exceptions when the callback is processed.

    1) Exclude OIDC callback paths from the route-tenant middleware

    In both Blazor Server UI and (if you added similar logic there) AuthServer, modify the middleware shown in the article so it skips authentication callback endpoints.

    Example (based on the article’s app.Use(async (httpContext, next) => { ... }) middleware):

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
    
        app.Use(async (httpContext, next) =>
        {
            // Exclude OIDC endpoints from tenant route/pathbase rewriting:
            var path = httpContext.Request.Path;
    
            if (path.StartsWithSegments("/signin-oidc") ||
                path.StartsWithSegments("/signout-callback-oidc") ||
                path.StartsWithSegments("/Account") ||
                path.StartsWithSegments("/connect")) // if needed
            {
                await next();
                return;
            }
    
            // Your existing tenant-from-route PathBase logic (from the community article) here...
            await next();
        });
    
        app.UseRouting();
        // ...
    }
    

    This prevents the route-based tenant middleware from interfering with /signin-oidc (and related endpoints), which is the safest approach.

    2) Keep the OIDC callback at the application root (/signin-oidc)

    Do not try to make the callback tenant-prefixed (e.g. /Tenant1/signin-oidc). Let it stay at /signin-oidc, and resolve tenant after sign-in using your normal mechanisms (cookie/current user, etc.). With the exclusion above, the callback will be processed consistently.

    3) Don’t “fix” this by disabling antiforgery globally

    Disabling antiforgery is not recommended for this scenario; the correct fix is to ensure the OIDC callback request is not mutated by the tenant-from-route pipeline.


    Relevant references (validated):

    • https://abp.io/community/articles/ah7oru97
    • https://abp.io/docs/latest/framework/infrastructure/csrf-anti-forgery
    • https://abp.io/support/questions/10739/Multi-tenant-authentication-provider-selection-based-on-route-parameter

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    The exception comes from endpoint routing. A broad route in your Blazor app — a page routed on something like /{__tenant} — also matches /signin-oidc, and Razor component endpoints accept POST and require antiforgery validation by default. The OIDC form_post callback is not an application form, so it carries no antiforgery token, and in the current pipeline that validation runs before the OpenID Connect handler gets to consume the callback.

    Move app.UseAntiforgery() after both app.UseAuthentication() and app.UseAuthorization() in OnApplicationInitialization of your Blazor module:

    app.UseRouting();
    app.MapAbpStaticAssets();
    app.UseAbpSecurityHeaders();
    app.UseAuthentication();
    
    if (MultiTenancyConsts.IsEnabled)
    {
        app.UseMultiTenancy();
    }
    
    app.UseDynamicClaims();
    app.UseAuthorization();
    app.UseAntiforgery();
    

    That is the placement ASP.NET Core requires, and it keeps antiforgery validation on your own Blazor forms — routing has already picked the endpoint, and the middleware still runs before the endpoint executes.

    One more thing that comes with the route-based tenant approach, separate from the exception above: the antiforgery cookie takes its path from Request.PathBase. Once the tenant middleware sets PathBase = /Tenant1, the cookie is scoped to /Tenant1, and a form rendered under the tenant path but posted to a root path fails validation with a 400. Pin the path on each host where that happens:

    using Microsoft.AspNetCore.Antiforgery;
    
    context.Services.Configure<AntiforgeryOptions>(options =>
    {
        options.Cookie.Path = "/";
    });
    

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 24, 2026, 12:09
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.