I have been battling with this issue for two days now and I need assitance.
Observed Problem
- Browser to my site in ingognito
- First page load → OK
- Click “Sign in” (public login page)
- Submitting credentials triggers HTTP 400 and ~/Views/Error/404 or 400.cshtml.
- Console log excerpt:
Antiforgery token validation failed. Validation of the provided antiforgery token failed. The cookie token and the request token were swapped. Identity.Application was not authenticated. Failure message: Unprotect ticket failed
Environment
| Item | Details |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| ABP version | 9.2.2 (Commercial) |
| Template | Blazor Hybrid (Account Public + Admin Pro + LeptonX) |
| Elsa Studio | v3 – integrated as standalone WASM under /elsa/…
|
| Hosting | Azure Container Apps (ACA) – single container, Linux |
| Ingress | external=true
, targetPort=8080
, transport=auto
|
| Probes | /health
(liveness) & /health/ready
(readiness/startup) |
| Data Protection | Keys persisted to Azure Blob Storage via Azure.Extensions.AspNetCore.DataProtection.Blobs
, user‑assigned managed identity |
| Forwarded Headers | Middleware added first: app.UseForwardedHeaders()
; options include XForwardedProto
, XForwardedFor
, XForwardedHost
|
| Antiforgery | HeaderName = "X-XSRF-TOKEN"
, Cookie.Name = "XSRF-TOKEN"
, SecurePolicy = Always
, SameSite = None
|
| DataProtection code | .SetApplicationName("YourSite")
+ .PersistKeysToAzureBlobStorage(blobClient)
|
| Cookies | Application cookie unchanged; antiforgery cookie now present |
HttpOverrides
trace shows Scheme=https
and correct host!
Relevant Code Snippets
This is the code I have in my BlazorModule.cs file
ConfigureServices()
// 1️⃣ Forwarded‑Header options (ACA IPs change frequently)
services.Configure<ForwardedHeadersOptions>(o =>
{
o.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto |
ForwardedHeaders.XForwardedHost;
o.KnownNetworks.Clear(); // allow any ingress IP
o.KnownProxies.Clear();
o.ForwardLimit = null; // unlimited hops
});
// 2️⃣ Data‑Protection keys → Azure Blob
var blobClient = new BlobClient(new Uri(cfg["DataProtection:BlobUri"]),
new DefaultAzureCredential(new DefaultAzureCredentialOptions {
ManagedIdentityClientId = cfg["DataProtection:ManagedIdentityClientId"]
}));
services.AddDataProtection()
.SetApplicationName("YourSite")
.PersistKeysToAzureBlobStorage(blobClient);
// 3️⃣ Antiforgery settings
services.AddAntiforgery(o =>
{
o.HeaderName = "X-XSRF-TOKEN";
o.Cookie.Name = "XSRF-TOKEN";
o.Cookie.SameSite = SameSiteMode.None;
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
// 4️⃣ Pin discriminator after all modules
services.PostConfigure<DataProtectionOptions>(o =>
{
o.ApplicationDiscriminator = "YourSite";
});
OnApplicationInitialization (first lines)
var app = context.GetApplicationBuilder();
// 1️⃣ MUST be first – handle X‑Forwarded‑* from ACA
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto |
ForwardedHeaders.XForwardedHost,
KnownNetworks = { }, KnownProxies = { }, ForwardLimit = null
});
// 2️⃣ Ensure HTTPS inside cluster
app.Use(async (ctx, next) =>
{
if (!ctx.Request.IsHttps)
{
ctx.Response.Redirect($"https://{ctx.Request.Host}{ctx.Request.Path}{ctx.Request.QueryString}", false);
return;
}
await next();
});
app.UseHttpsRedirection();
// … ABP default pipeline continues …
What we tried & outcome
| Attempt | Outcome |
| --------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| Persist keys + SetApplicationName
| ✅ Key‑ring loads without “key not found”. |
| PostConfigure<DataProtectionOptions>
last | ✅ Logs show application isolator: YourSite
. |
| UseForwardedHeaders
first | ✅ Trace says Request IsHttps = True
. |
| Antiforgery header & secure cookie config | ❌ Still get 400 & “cookie token and request token were swapped”. |
| Temporarily set CookieSecurePolicy = None
| Browser blocks cookie (SameSite=None
requires Secure) – still 400. |
| Confirmed via DevTools: request sends no XSRF‑TOKEN
cookie; only the form header. | |
Questions for ABP Support
- Is there ABP middleware in Blazor‑Hybrid that rewrites or clears the antiforgery cookie after
UseForwardedHeaders
, causing the browser to miss it? - Does the Account Public login page in 9.2.2 expect a different antiforgery header configuration than the one we applied?
- Is any additional ABP setting required when running behind Envoy (ACA) to keep the
XSRF‑TOKEN
cookie? - How can we enable even more detailed tracing for ABP’s antiforgery pipeline to see why the cookie is not returned?
- Is ABP explicitly expecting a different antiforgery token pattern or explicitly using an internal header?
- Could the separate Elsa Studio WASM app (added
_Host.cshtml
) under Elsa interfere with antiforgery for Account routes?
4 Answer(s)
-
0
- In ABP, the antiforgery system is enabled by default and uses a cookie (default:
XSRF-TOKEN
) and a request header (default:RequestVerificationToken
). Your custom headerX-XSRF-TOKEN
and cookie name are valid, but you must ensure the client-side code (JS or Blazor) reads the cookie and sends it in the header for every POST/PUT request. If the header is sent but the cookie is missing, validation fails. - The error “cookie token and request token were swapped” typically means the antiforgery system received the tokens in the wrong order, or the cookie was not present at all. This can happen if the browser blocks the cookie (e.g., due to
SameSite=None
withoutSecure
, or proxy misconfiguration). - Your configuration for
Cookie.SameSite = None
andCookie.SecurePolicy = Always
is correct for cross-site scenarios, but only if HTTPS is enforced end-to-end. If any hop is HTTP, the browser will not send the cookie. - When running behind Azure Container Apps (Envoy), ensure that:
UseForwardedHeaders
is the very first middleware.- The
X-Forwarded-Proto
header is set tohttps
by the ingress. - The application always sees requests as HTTPS (
Request.IsHttps == true
).
- If the antiforgery cookie is not being set or sent, check:
- The initial GET to the login page must return a
Set-Cookie: XSRF-TOKEN=...; SameSite=None; Secure
header. - The browser must accept and store this cookie. Use DevTools to confirm.
- The POST request must include both the cookie and the header.
- The initial GET to the login page must return a
- There is no ABP middleware that rewrites or clears the antiforgery cookie after
UseForwardedHeaders
. However, if the pipeline is misordered or the request is not seen as HTTPS, the cookie may not be set. - The Account Public login page expects the antiforgery header to match the configured name. If you changed it to
X-XSRF-TOKEN
, ensure all client-side code (including Blazor and any JS) uses this header. - No additional ABP setting is required for Envoy/ACA, but you must ensure forwarded headers and HTTPS are handled correctly.
- For more detailed tracing, enable logging for
Microsoft.AspNetCore.Antiforgery
andVolo.Abp.AspNetCore.Mvc.AntiForgery
at theDebug
orTrace
level in your logging configuration. - ABP does not use a different antiforgery token pattern; it uses the standard ASP.NET Core antiforgery system.
- If Elsa Studio WASM is served from the same domain and shares cookies, it could interfere if it changes or clears cookies, but this is unlikely unless it explicitly manipulates the antiforgery cookie.
Troubleshooting Steps:
- Confirm the initial GET to the login page sets the
XSRF-TOKEN
cookie withSameSite=None; Secure
. - Confirm the POST request includes both the
XSRF-TOKEN
cookie and theX-XSRF-TOKEN
header. - Ensure all requests are seen as HTTPS by the app (check
Request.IsHttps
). - If using a custom header, ensure all ABP and client code use the same header name.
- If the problem persists only in incognito or after a cold start, it may be a timing or caching issue—ensure the cookie is set before the POST.
- If using multiple containers or instances, ensure all share the same data protection keys and application name/discriminator.
Example: Logging Configuration
// appsettings.json "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore.Antiforgery": "Debug", "Volo.Abp.AspNetCore.Mvc.AntiForgery": "Debug" } }
References:
- ABP CSRF/Anti-Forgery System
- Support: Antiforgery token mismatch on email verification
- Support: ERR_TOO_MANY_REDIRECTS and Antiforgery Token Validation Failed
- Patch for Chrome Login Issue (SameSite Cookie Problem)
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.
- In ABP, the antiforgery system is enabled by default and uses a cookie (default:
-
0
hi
The cookie token and the request token were swapped
This error indicates that the
Antiforgerytoken
in the header/form is using theAntiforgerytoken
from cookies.Can you share an online website? I will test it online.
liming.ma@volosoft.com
Thanks
-
0
Thank you liming but I figured this out finally. It was _Host.cshtml from Elsa that was causing my issue
I hade
builder.MapFallbackToPage("/_Host");
and then had to do things arround that.
-
0
Great 👍