ASP.NET Core Practice Test

โ–ถ

Understanding how to implement AntiForgeryToken in ASP.NET Core is one of the most essential security skills any .NET developer can master. Cross-Site Request Forgery (CSRF) attacks trick authenticated users into submitting malicious requests without their knowledge, and without proper protection your application is exposed to session hijacking, unauthorized data modification, and account takeover. ASP.NET Core ships with a built-in antiforgery middleware that generates cryptographically signed tokens to verify that every state-changing HTTP request genuinely originates from your own UI and not from an attacker-controlled page. Getting this right is not optional in production applications.

Understanding how to implement AntiForgeryToken in ASP.NET Core is one of the most essential security skills any .NET developer can master. Cross-Site Request Forgery (CSRF) attacks trick authenticated users into submitting malicious requests without their knowledge, and without proper protection your application is exposed to session hijacking, unauthorized data modification, and account takeover. ASP.NET Core ships with a built-in antiforgery middleware that generates cryptographically signed tokens to verify that every state-changing HTTP request genuinely originates from your own UI and not from an attacker-controlled page. Getting this right is not optional in production applications.

CSRF vulnerabilities are consistently listed in the OWASP Top 10, and real-world breaches attributed to them have cost organizations millions of dollars in regulatory fines and reputational damage. The attack vector is surprisingly simple: an attacker embeds an invisible form or image tag on a third-party site, and when an authenticated victim visits that page their browser automatically sends the victim's cookies to your server. Without a server-generated, request-specific token that the attacker cannot read or predict, your server has no reliable way to distinguish the legitimate request from the forged one.

ASP.NET Core's antiforgery system solves this by issuing two complementary tokens at form-rendering time. The first token is stored in an HTTP-only cookie, and the second is embedded directly in the HTML form as a hidden field.

When the form is submitted, the framework validates that both tokens are present and that they match according to a cryptographic relationship derived from the user's identity and a server-side key. An attacker who can inject a form but cannot read your site's cookies โ€” due to the Same-Origin Policy โ€” is unable to forge the matching pair and the request is rejected with a 400 Bad Request.

Learning about antiforgerytoken in asp.net core is valuable not only for protecting your own applications but also for clearing security-focused interview questions and certification scenarios. Interviewers frequently ask candidates to walk through the CSRF threat model, explain the double-submit cookie pattern, or demonstrate how to configure antiforgery options in Program.cs. Developers who can articulate why the middleware is needed โ€” and not just paste the attribute โ€” consistently stand out from their peers and move into senior and architect roles more quickly.

This guide walks through every layer of the ASP.NET Core antiforgery stack: how the middleware is registered, how the Razor tag helpers automatically embed tokens in forms, how controller actions validate tokens using the [ValidateAntiForgeryToken] attribute, and how to extend the defaults for SPA architectures and API endpoints. You will also learn how to write integration tests that confirm antiforgery protection is active, which common misconfigurations silently disable protection, and how to debug the opaque 400 errors that appear when tokens are missing or expired.

Throughout this article, practical C# code snippets illustrate each concept so you can drop working examples into your own projects immediately. Every section builds on the previous one, starting from the simplest Razor Pages setup and progressing to custom token providers, per-request header injection for Angular or React front ends, and multi-tenant scenarios where each tenant's requests must be isolated from one another. By the end you will have a complete mental model of how ASP.NET Core keeps your users safe from one of the web's most persistent and exploitable attack classes.

Whether you are preparing for a technical interview, hardening an existing application before a security audit, or simply building good habits from the start of a greenfield project, the depth of coverage in this guide ensures you leave with actionable knowledge rather than surface-level familiarity. Security is not a feature to bolt on at the end of a sprint โ€” it is an architectural decision that affects every form, every API endpoint, and every user session in your system, and the antiforgery system is the first line of defense you must get right.

ASP.NET Core Antiforgery by the Numbers

โš ๏ธ
Top 10
OWASP Ranking
๐Ÿ›ก๏ธ
2 tokens
Double-Submit Pattern
๐Ÿ’ป
1 line
Razor Pages Setup
โฑ๏ธ
< 1 ms
Token Validation Overhead
๐Ÿ“Š
400
HTTP Status on Failure
Test Your AntiForgeryToken Knowledge โ€” Free ASP.NET Core Practice Questions

How the Antiforgery System Works

โš™๏ธ

Call builder.Services.AddAntiforgery() in Program.cs to register the IAntiforgery service. ASP.NET Core's AddControllersWithViews() and AddRazorPages() call this automatically, but explicit registration lets you configure cookie names, header names, and SuppressXFrameOptionsHeader options in one place.

๐Ÿ”‘

When a Razor view or Page renders a form, the AntiforgeryTagHelper reads the IAntiforgery service and generates two linked tokens. The request token is embedded as a hidden <input> field in the HTML. The cookie token is set as an HTTP-only, SameSite=Strict cookie sent in the Set-Cookie response header.

๐Ÿ“ค

When the user submits the form the browser sends both the hidden field value (in the POST body) and the antiforgery cookie. An attacker on a different origin can trigger the cookie to be sent automatically, but they cannot read the hidden field value embedded in your HTML because the Same-Origin Policy blocks cross-origin reads.

โœ…

The [ValidateAntiForgeryToken] attribute on the controller action (or the AutoValidateAntiforgeryToken filter applied globally) calls IAntiforgery.ValidateRequestAsync(). The middleware verifies that both tokens are present, decrypts the cookie token, and confirms the cryptographic relationship between the two tokens using the user's identity as part of the key material.

๐Ÿ›ก๏ธ

If validation passes, the action method executes normally. If either token is missing, tampered with, or expired, ASP.NET Core throws an AntiforgeryValidationException that results in a 400 Bad Request response before your application code ever runs, ensuring malicious requests never reach your business logic layer.

Configuring the antiforgery system in Program.cs gives you precise control over every aspect of token generation and validation. The most important options live in the AntiforgeryOptions class, which you pass as a lambda to builder.Services.AddAntiforgery(). The HeaderName property is critical for SPA and API scenarios: set it to something like "X-XSRF-TOKEN" and your Angular or React client can send the token as an HTTP header rather than embedding it in a form body, which is the standard pattern for AJAX-heavy applications that never perform traditional HTML form posts.

The Cookie property on AntiforgeryOptions gives you full control over the antiforgery cookie behavior. In production you should always set Cookie.SecurePolicy to CookieSecurePolicy.Always to ensure the cookie is only sent over HTTPS connections. Setting Cookie.SameSite to SameSiteMode.Strict provides an additional defense-in-depth layer because modern browsers will refuse to send same-site strict cookies on cross-origin requests at all, complementing the token check with a browser-enforced policy. You should also give the cookie a memorable, application-specific name rather than relying on the default .AspNetCore.Antiforgery.XXXXXXXX pattern, which makes debugging and monitoring much easier in production log streams.

For Razor Pages applications the antiforgery middleware is enabled by default when you call builder.Services.AddRazorPages(). Every Razor Page that uses the asp-action or form tag helper automatically receives the hidden antiforgery input field โ€” you do not need to do anything extra for standard page submissions. However, you must ensure that the middleware pipeline includes app.UseAntiforgery() if you are working with minimal API or Blazor configurations, because in those hosting models the antiforgery middleware is not automatically added to the pipeline and must be explicitly placed after app.UseRouting() and before your endpoint mappings.

MVC controller applications require slightly more ceremony. The recommended approach for MVC is to apply a global filter rather than decorating every individual action with [ValidateAntiForgeryToken]. Add the AutoValidateAntiforgeryTokenAttribute to the global filter collection in Program.cs using builder.Services.AddControllersWithViews(options => options.Filters.Add<AutoValidateAntiforgeryTokenAttribute>()). This ensures protection is on by default for all POST, PUT, PATCH, and DELETE actions, and you only need the [IgnoreAntiforgeryToken] attribute on the rare actions that must accept cross-origin requests, such as webhook endpoints that receive payloads from third-party services with their own HMAC signature verification.

One subtle but important configuration detail concerns the SuppressXFrameOptionsHeader property. By default the antiforgery service sets the X-Frame-Options: SAMEORIGIN header on all responses that generate antiforgery tokens, which prevents your pages from being embedded in iframes on other origins โ€” a useful secondary defense against clickjacking. However, if you have a legitimate need to allow iframe embedding from trusted partner origins you can set SuppressXFrameOptionsHeader to true and manage the Content-Security-Policy frame-ancestors directive yourself, giving you more granular control over which origins may embed your pages while still maintaining antiforgery token protection for form submissions.

Key rotation is an often overlooked configuration topic. The antiforgery token signing key is derived from the ASP.NET Core Data Protection key ring. If you are running multiple server instances behind a load balancer โ€” which is extremely common in cloud deployments โ€” you must configure a shared, persistent Data Protection key store so that a token generated by one instance can be validated by any other instance.

Without this, users whose requests are routed to a different server than the one that generated their form will experience seemingly random 400 errors that are very difficult to diagnose without understanding the Data Protection dependency. Azure Key Vault, Azure Blob Storage, and AWS Parameter Store are all popular persistent key ring backends.

Finally, consider the interaction between antiforgery and caching. If you cache entire HTML responses at the CDN or reverse proxy layer, you risk serving stale antiforgery tokens from the cache. A token that was valid for user A should never be served to user B, and a token that was generated yesterday may have a different Data Protection key than today's key ring.

The standard mitigation is to either exclude form-containing pages from caching entirely, or to use the Vary: Cookie header to ensure each unique session gets its own cached response. Alternatively, adopt a pattern where the initial page load contains no token and a subsequent lightweight AJAX call retrieves a fresh token immediately before form submission, which is compatible with aggressive edge caching.

ASP.NET Core Authentication & Authorization 1
Test your knowledge of ASP.NET Core auth fundamentals including antiforgery and CSRF protection
ASP.NET Core Authentication & Authorization 2
Intermediate questions covering token validation, cookie security, and identity configuration

Token Strategies: MVC, Razor Pages, and API Endpoints

๐Ÿ“‹ Razor Pages

Razor Pages is the most friction-free environment for antiforgery because the framework handles nearly everything automatically. When you declare a form with the <form method="post"> tag in a .cshtml file, the Razor tag helper engine detects the POST method and automatically injects a hidden <input type="hidden" name="__RequestVerificationToken"> field. On the handler side, any PageModel method named OnPost, OnPostAsync, or following that naming convention is automatically protected โ€” you do not need to apply [ValidateAntiForgeryToken] because the Razor Pages infrastructure applies validation globally to all handler methods by default.

The only common Razor Pages pitfall is AJAX form submission. If you serialize your form with JavaScript and submit it via fetch() or XMLHttpRequest, the hidden field is included in the serialized data automatically, but you must ensure your fetch call uses the correct Content-Type header so ASP.NET Core's model binding finds the token in the request body. Alternatively, read the antiforgery cookie value with JavaScript (the non-HTTP-only token cookie, if configured), and add it as a request header named X-XSRF-TOKEN alongside configuring HeaderName in AntiforgeryOptions to match that header name.

๐Ÿ“‹ MVC Controllers

In classic MVC, the @Html.AntiForgeryToken() HTML helper or the <form asp-action="..."> tag helper both inject the hidden verification field into your rendered HTML. On the controller action you must explicitly opt in to validation by decorating the action or the entire controller class with [ValidateAntiForgeryToken]. A better approach for large applications is to register AutoValidateAntiforgeryTokenAttribute as a global filter so that all unsafe HTTP verbs are protected by default and you only exempt specific actions using [IgnoreAntiforgeryToken] where genuinely necessary, such as on public API endpoints or webhook receivers.

When working with AJAX in MVC, inject the antiforgery token into your JavaScript context by reading it from a meta tag rendered in the layout: <meta name="csrf-token" content="@antiforgery.GetAndStoreTokens(HttpContext).RequestToken">. Your jQuery or fetch-based code then reads this meta tag value and attaches it to every AJAX request as the X-RequestVerificationToken header. Configure HeaderName in AntiforgeryOptions to match, and the server automatically validates header-delivered tokens alongside body-delivered ones, giving you a clean, consistent pattern across both traditional form posts and AJAX calls.

๐Ÿ“‹ Minimal APIs & SPAs

Minimal APIs introduced in .NET 6 and refined through .NET 8 require explicit antiforgery setup because they do not inherit the MVC filter pipeline. Call app.UseAntiforgery() in your middleware chain and then apply the WithRequestTimeout() or ValidateAntiforgeryToken() endpoint extension method on each route group that needs protection. For token distribution, expose a dedicated GET endpoint โ€” for example GET /antiforgery/token โ€” that calls IAntiforgery.GetAndStoreTokens() and returns the request token as JSON. Your SPA calls this endpoint on startup or after login and stores the token in memory (never localStorage) for use on subsequent mutating requests.

Angular applications benefit from the built-in HttpClientXsrfModule, which automatically reads a cookie named XSRF-TOKEN and attaches its value as the X-XSRF-TOKEN header on every non-GET request. Configure ASP.NET Core to write the antiforgery token to a JavaScript-readable (non-HTTP-only) cookie with that exact name, and set HeaderName to X-XSRF-TOKEN in AntiforgeryOptions. React applications follow the same pattern using axios's xsrfCookieName and xsrfHeaderName configuration properties. This cookie-to-header transport pattern is the industry standard for SPA frameworks and requires no manual token management code beyond the initial configuration on both the server and client sides.

Antiforgery Token Protection: Strengths and Limitations

Pros

  • Prevents CSRF attacks by requiring a server-generated cryptographic token that attackers cannot predict or forge from a different origin
  • Built into ASP.NET Core with zero additional NuGet packages โ€” AddRazorPages() and AddControllersWithViews() register the service automatically
  • Razor tag helpers inject the hidden field automatically into forms, eliminating the need for manual token management in most Razor scenarios
  • Supports both cookie-and-field (traditional forms) and cookie-and-header (AJAX/SPA) transport patterns from the same configuration
  • Tokens are tied to the user's identity using Data Protection, so a token issued for one authenticated user cannot be reused by another
  • Negligible performance overhead โ€” HMAC-SHA256 token validation typically completes in under one millisecond even on modest hardware

Cons

  • Requires shared Data Protection key store in multi-server load-balanced deployments, adding infrastructure configuration complexity
  • Token expiration and rotation can cause confusing 400 errors for users with long-lived browser sessions who submit stale forms hours later
  • Incompatible with fully cached HTML pages at the CDN layer unless you architect a separate token-fetch endpoint for pre-cached pages
  • Webhook and third-party API callback endpoints must be explicitly excluded using [IgnoreAntiforgeryToken], which can be forgotten during development
  • AJAX patterns require additional JavaScript setup to read and forward the token, especially in vanilla JS projects without a framework
  • Does not protect against all request-forgery scenarios โ€” XSS vulnerabilities on the same origin can still read the hidden token from the DOM
ASP.NET Core Authentication & Authorization 3
Advanced scenarios including antiforgery in SPAs, API security, and token lifecycle management
ASP.NET Core Configuration & Environments 1
Practice questions on app configuration, environment variables, and security middleware setup

ASP.NET Core Antiforgery Implementation Checklist

Register antiforgery services with builder.Services.AddAntiforgery() and configure CookieSecurePolicy.Always for HTTPS-only cookie transport.
Set Cookie.SameSite to SameSiteMode.Strict in AntiforgeryOptions to enable browser-level cross-origin cookie blocking as a secondary defense.
Apply AutoValidateAntiforgeryTokenAttribute as a global MVC filter so all POST, PUT, PATCH, and DELETE actions are protected by default.
Call app.UseAntiforgery() explicitly in minimal API or Blazor applications where the middleware is not automatically added to the pipeline.
Configure a shared Data Protection key store (Azure Blob, Redis, or AWS SSM) for all load-balanced multi-instance deployments.
Set HeaderName in AntiforgeryOptions to X-XSRF-TOKEN and configure your SPA framework (Angular HttpClientXsrfModule or axios xsrfHeaderName) to match.
Expose a dedicated GET /antiforgery/token endpoint in SPA projects that returns a fresh token after authentication or page load.
Apply [IgnoreAntiforgeryToken] explicitly to webhook receiver actions and document why the exemption is safe (third-party HMAC, IP allow-list, etc.).
Exclude HTML form pages from full-page CDN caching or use Vary: Cookie to ensure each session receives its own token-containing response.
Write integration tests using WebApplicationFactory that confirm a 400 response when the antiforgery token is absent from POST requests.
Always Use Global Filters Over Per-Action Attributes

Applying [ValidateAntiForgeryToken] individually on every action is error-prone โ€” it takes just one forgotten attribute to leave a state-changing endpoint unprotected. Register AutoValidateAntiforgeryTokenAttribute as a global filter in Program.cs and use [IgnoreAntiforgeryToken] only on the small number of actions that have a documented, reviewed reason for bypassing protection. This opt-out model is dramatically safer than the opt-in model and aligns with the secure-by-default principle that guides all modern ASP.NET Core security design decisions.

Testing and debugging antiforgery failures is a skill that separates developers who truly understand the system from those who merely copy configuration snippets. The most common symptom is a 400 Bad Request with the message "The required anti-forgery form field '__RequestVerificationToken' is not present" or "The anti-forgery cookie token and form field token do not match." These messages appear in the ASP.NET Core diagnostic middleware output when you enable detailed errors in development, but in production they are suppressed to avoid leaking implementation details. Knowing how to reproduce and diagnose them systematically is essential.

Integration testing with WebApplicationFactory is the gold standard for verifying antiforgery protection. Write a test that posts to a protected endpoint without including the token and assert that the response status code is 400. Then write a second test that properly fetches the form, extracts the token from the response HTML using an HTML parser like AngleSharp, re-includes it in the POST body, and asserts that the response is 200 or a redirect.

These two tests together prove that protection is active and that the happy path still works. Without both tests you cannot be sure whether the 200 you see in the happy-path test means protection is working or means protection is silently disabled.

A tricky debugging scenario occurs when your application uses both cookie authentication and antiforgery tokens and the user logs out. After logout the antiforgery cookie is cleared along with the authentication cookie, but if the user navigates back using the browser's back button they may still see the old form with the old token.

When they submit that form, validation fails because the cookie-side of the double-submit pair is missing. The correct fix is to either redirect after logout to a fresh page rather than relying on cache, or to implement a client-side listener that detects navigation to cached pages and reloads them. This is a genuine usability concern in long-running applications with active user sessions.

Another common debugging challenge arises with partial views and Blazor components rendered inside traditional Razor Pages layouts. If a partial view contains a form but is rendered in a context where the antiforgery cookie has not yet been set โ€” for example, in a server-side streamed response โ€” the tag helper may generate a token but the cookie may not arrive at the browser before the form is submitted.

In streaming rendering scenarios, ensure you call IAntiforgery.SetCookieTokenAndHeader(HttpContext) explicitly at the start of the response pipeline to guarantee the cookie is set before any partial content containing form tokens is flushed to the client.

Token validation errors can also appear in legitimate scenarios after a server-side application restart when you have not configured persistent Data Protection keys. Each restart generates a new key ring, making all previously issued antiforgery tokens invalid. Users who had a form open in their browser before the restart will get a 400 when they submit.

This is not a bug โ€” it is the correct security behavior โ€” but it degrades user experience and can spike your error monitoring dashboards after a deployment. Mitigate it by configuring persistent Data Protection storage and setting an appropriate key lifetime using ProtectKeysWithAzureKeyVault or an equivalent provider for your cloud platform.

Logging is your most powerful debugging tool. Enable Microsoft.AspNetCore.Antiforgery logging at the Debug level in your appsettings.Development.json by adding "Microsoft.AspNetCore.Antiforgery": "Debug" to the Logging.LogLevel section. This causes ASP.NET Core to emit detailed messages at each stage of the token validation lifecycle, including which specific check failed and why. Combined with the request correlation ID in your distributed tracing setup, you can trace exactly what happened to a specific user's request from the moment the form was rendered to the moment validation succeeded or failed, giving you the full context needed to diagnose even the most subtle configuration errors.

Finally, when working in development with Swagger or Postman to test API endpoints protected by antiforgery tokens, remember that these tools do not automatically handle the double-submit cookie pattern. You must first make a GET request to your token endpoint, copy the returned token value, and then include it as either a form field or a request header on your subsequent mutating requests.

Creating a Postman pre-request script that automatically fetches a fresh token before every POST or PUT request saves significant time during development and ensures you never waste time debugging a 400 that is simply caused by forgetting to update your Postman environment variable with a fresh token value.

Advanced antiforgery patterns unlock more sophisticated security architectures that go well beyond the basic hidden-field approach. One powerful pattern is per-form token binding, where you supply a custom FormFieldName or HeaderName per form type to ensure that a token issued for your "change email" form cannot be replayed against your "change password" form.

ASP.NET Core does not enforce this out of the box, but you can implement it by including an additional purpose string in a custom IAntiforgeryAdditionalDataProvider implementation, which causes the framework to incorporate that purpose into the cryptographic token derivation, making cross-form token reuse impossible even within the same session.

The IAntiforgeryAdditionalDataProvider interface is the primary extension point for customizing token generation and validation logic. Implement GetAdditionalData() to embed additional claims โ€” such as the user's current IP address, a device fingerprint, or the specific form name โ€” into the token payload. Implement ValidateAdditionalData() to verify those claims on submission. This allows you to build step-up security flows where a sensitive transaction form requires not only a valid antiforgery token but also a token that was generated on the same device and IP address, providing defense in depth against token theft via session sharing or XSS-facilitated token exfiltration.

Multi-tenant SaaS applications introduce an additional concern: tenant isolation in antiforgery tokens. If your application serves multiple tenants from the same host and you use a shared antiforgery cookie domain, a token generated in the context of Tenant A should never be usable in the context of Tenant B. Solve this by including the tenant ID in the additional data provider, so the cryptographic derivation is tenant-scoped. Alternatively, use separate subdomains per tenant with distinct antiforgery cookie names scoped to each subdomain, which gives you browser-enforced isolation for free at the cost of more complex DNS and TLS certificate management.

Blazor Server applications have a unique relationship with antiforgery because the WebSocket-based SignalR connection handles most state changes after the initial page load, bypassing the traditional HTTP request-response cycle entirely. The antiforgery token is still needed for the initial form post that establishes the Blazor circuit, and for any non-Blazor HTTP endpoints in the same application. Within the Blazor component tree, CSRF protection is provided by the SignalR connection's inherent same-origin restriction combined with the circuit's cryptographic connection ID, so you do not need antiforgery tokens on individual Blazor component event handlers.

Blazor WebAssembly applications running as SPAs follow the same pattern as other SPA frameworks: fetch a token from a server endpoint and include it on every mutating HTTP request. The key Blazor WebAssembly difference is that you can inject IHttpClientFactory and configure a custom DelegatingHandler that automatically attaches the antiforgery token to every request made to your own API.

This handler fetches a fresh token on first use and caches it in memory for the session lifetime, refreshing it if a 400 response indicates the token has expired. This approach produces clean, centralized token management with no boilerplate scattered across individual component event handlers or service method calls.

For microservice architectures where multiple backend services share a common API gateway, consider centralizing antiforgery token issuance in the gateway layer rather than implementing it independently in each downstream service. The gateway can expose a single /token endpoint, issue tokens signed with a shared key distributed to all downstream services via a secrets manager, and each downstream service validates incoming tokens against that shared key without needing to generate tokens themselves. This architectural pattern reduces duplication, centralizes audit logging of token issuance events, and makes key rotation a single-point operation rather than a coordinated multi-service deployment.

Token revocation is a capability that the default ASP.NET Core antiforgery system does not provide โ€” tokens remain valid until they expire based on the Data Protection key lifetime. If you need immediate revocation after a security event such as a password change or suspicious login, you must implement it yourself. One approach is to include a per-user nonce in the additional data provider that is stored in a distributed cache like Redis.

After a security-sensitive event, increment the user's nonce in Redis. During token validation, your custom ValidateAdditionalData() method checks the stored nonce against the token's nonce and rejects any token issued before the most recent increment, effectively revoking all outstanding tokens without a full key rotation. This pattern provides fine-grained revocation with minimal infrastructure overhead.

Practice ASP.NET Core Security Questions โ€” Free CSRF and Antiforgery Quiz

Putting antiforgery knowledge into practice requires more than reading documentation โ€” it demands working through realistic scenarios that surface the edge cases and failure modes you will encounter in production. Start by building a minimal ASP.NET Core Razor Pages application with a single form that changes a user's email address. Verify that submitting the form without a token returns 400, that submitting it with an expired token also returns 400, and that submitting it with a valid token succeeds. This three-case test harness gives you immediate, hands-on confidence in the token lifecycle before moving on to more complex scenarios.

Once the basics work, add a JavaScript-based form enhancement that submits via fetch() and observe whether the token is correctly included in the fetch body. Many developers are surprised to discover that the Fetch API does not automatically serialize form fields the same way a native form submission does โ€” you must explicitly construct a FormData object from the form element and pass it as the fetch body to ensure all hidden fields including the antiforgery token are included. Alternatively, use the URLSearchParams constructor with the form element to produce an application/x-www-form-urlencoded body that includes all fields.

Next, deliberately misconfigure your application by removing the global AutoValidateAntiforgeryTokenAttribute filter and observe that POST requests succeed without any token. This exercise, safe to perform only in a local development environment, reinforces exactly why the opt-out model is safer than the opt-in model. The silence with which unprotected endpoints accept unauthenticated state changes is exactly what attackers exploit in production systems where a single overlooked [ValidateAntiForgeryToken] attribute leaves a door open for CSRF attacks.

For interview preparation, practice explaining the double-submit cookie pattern without referring to notes. Be able to describe what two tokens are involved, where each one travels in the HTTP request, why an attacker on a different origin cannot forge a matching pair despite being able to trigger the cookie to be sent automatically, and how the cryptographic relationship between the two tokens is established.

Interviewers at senior and staff engineer levels often follow this with a question about how the system behaves in a stateless load-balanced environment โ€” your answer should immediately reference Data Protection key sharing as the enabling infrastructure concern.

Study the relationship between antiforgery and the SameSite cookie attribute because this topic generates significant interview discussion. SameSite=Strict cookies are not sent on cross-origin navigations at all, which means a straightforward GET-triggered CSRF attack fails even without antiforgery tokens when SameSite=Strict is set.

However, SameSite alone is not sufficient because older browsers that predate the SameSite standard do not enforce it, because some legitimate cross-origin flows require Lax or None settings, and because POST-based CSRF with same-site top-level navigation can still work in certain SameSite=Lax configurations. Antiforgery tokens provide a defense that works regardless of browser version or cookie attribute support.

When reviewing other developers' pull requests, look specifically for three antiforgery anti-patterns: controllers or actions decorated only with [HttpPost] but missing [ValidateAntiForgeryToken] in applications that rely on per-action attributes rather than global filters; forms whose action attribute points to a different origin, which means the antiforgery cookie will be sent but the hidden field will not be accessible to the receiving server; and AJAX handlers that include the antiforgery header on GET requests where it is unnecessary, which adds overhead and may cause confusion about which requests actually require token validation.

Finally, integrate antiforgery failure monitoring into your observability stack. Configure a custom middleware that catches AntiforgeryValidationException, logs the user's identity, IP address, and the specific request path to your structured logging provider, and increments a metric counter named csrf.validation.failure. Set up an alert that fires when this counter exceeds a baseline threshold โ€” a sudden spike may indicate an automated CSRF attack attempt against your application rather than legitimate user errors. This kind of proactive monitoring turns your antiforgery implementation from a passive defense mechanism into an active threat detection signal that feeds your security incident response process.

ASP.NET Core Configuration & Environments 2
Intermediate configuration scenarios including Data Protection setup and key storage for antiforgery
ASP.NET Core Configuration & Environments 3
Advanced multi-environment and security configuration patterns for production ASP.NET Core apps

Asp Net Core Questions and Answers

What is an AntiForgeryToken and why is it needed in ASP.NET Core?

An AntiForgeryToken is a cryptographically signed value that ASP.NET Core embeds in HTML forms and validates on form submission to prevent Cross-Site Request Forgery (CSRF) attacks. Without it, an attacker on a different website can trick an authenticated user's browser into submitting malicious form posts to your server using the victim's cookies. The token proves the request originated from your own UI because an attacker on a different origin cannot read the token value from your HTML.

How do I enable antiforgery validation globally in ASP.NET Core MVC?

Add AutoValidateAntiforgeryTokenAttribute to the global MVC filter collection in Program.cs: builder.Services.AddControllersWithViews(options => options.Filters.Add<AutoValidateAntiforgeryTokenAttribute>()). This automatically validates tokens on all POST, PUT, PATCH, and DELETE requests across every controller and action without requiring individual [ValidateAntiForgeryToken] attributes. Use [IgnoreAntiforgeryToken] on the specific actions that must accept cross-origin requests, such as webhook endpoints with their own HMAC signature verification.

Why do I get a 400 Bad Request error on form submission in ASP.NET Core?

A 400 Bad Request on form submission typically means the antiforgery token is missing or invalid. Common causes include: the form was rendered before the antiforgery cookie was set; the token expired because the Data Protection key ring was rotated; you are running multiple server instances without a shared Data Protection key store; or the form is being submitted via AJAX without including the hidden token field or the correct request header. Enable Debug-level logging for Microsoft.AspNetCore.Antiforgery to see the specific failure message.

How does antiforgery work with AJAX and fetch() in ASP.NET Core?

For AJAX submissions, serialize the form using FormData(formElement) and pass it as the fetch() body โ€” this automatically includes the hidden antiforgery field. Alternatively, configure a non-HTTP-only cookie containing the request token, read it with JavaScript, and send it as a custom header (e.g., X-XSRF-TOKEN). Set HeaderName in AntiforgeryOptions to match that header name. Angular's HttpClientXsrfModule and axios's xsrfCookieName/xsrfHeaderName properties automate this pattern for SPA frameworks.

Do I need antiforgery tokens on ASP.NET Core Web API endpoints?

Traditional JSON API endpoints consumed only by SPAs or mobile clients do not need antiforgery tokens if they require an Authorization header with a bearer token, because cross-origin scripts cannot set custom headers due to CORS preflight restrictions. However, if your API uses cookie-based authentication and is accessed via browser forms or AJAX without bearer tokens, antiforgery protection is necessary. Use the [IgnoreAntiforgeryToken] attribute selectively and document the reason, rather than disabling protection application-wide.

How do I configure antiforgery for a load-balanced multi-server ASP.NET Core deployment?

Configure a shared, persistent Data Protection key store so every server instance uses the same signing keys. Options include Azure Blob Storage with PersistKeysToAzureBlobStorage(), AWS Parameter Store, Redis with PersistKeysToStackExchangeRedis(), or a shared network file path. Without shared keys, a token generated by Server A cannot be validated by Server B, producing intermittent 400 errors for users whose requests are routed to a different instance than the one that generated their form. Protect the shared keys using Azure Key Vault or AWS KMS.

Can I use antiforgery tokens in Blazor applications?

Blazor Server handles most state changes over a SignalR WebSocket connection that is inherently protected by same-origin restrictions and the circuit's cryptographic ID, so per-event antiforgery tokens are not required inside Blazor components. However, antiforgery tokens are still needed for the initial HTTP form that establishes the connection and for any non-Blazor API endpoints in the application. Blazor WebAssembly apps act as SPAs and should use the cookie-to-header pattern with a token-fetch endpoint for API calls.

What is the difference between [ValidateAntiForgeryToken] and [AutoValidateAntiforgeryToken]?

[ValidateAntiForgeryToken] validates the antiforgery token on every HTTP method including GET, HEAD, and OPTIONS, which is overly broad and can cause problems. [AutoValidateAntiforgeryToken] only validates on state-changing methods: POST, PUT, PATCH, and DELETE. This matches the CSRF threat model perfectly since CSRF attacks can only exploit state-changing requests. Always prefer AutoValidateAntiforgeryToken, either as an attribute or registered as a global filter, because it provides correct protection without interfering with safe HTTP methods.

How does SameSite cookie attribute relate to antiforgery tokens?

SameSite=Strict prevents browsers from sending cookies on cross-origin requests, providing a complementary layer of CSRF protection. However, SameSite alone is insufficient because older browsers do not support it, some legitimate cross-origin flows require SameSite=Lax or None, and certain Lax-mode navigations still send cookies. Antiforgery tokens provide defense that works regardless of browser version. Use both: set Cookie.SameSite = SameSiteMode.Strict in AntiforgeryOptions AND enforce token validation, applying defense-in-depth rather than relying on either mechanism alone.

How can I test that antiforgery protection is working correctly?

Write integration tests using WebApplicationFactory with two cases: first, POST to a protected endpoint without a token and assert the response is 400 Bad Request. Second, GET the form page, extract the antiforgery token from the HTML response using AngleSharp or HtmlAgilityPack, include it in a subsequent POST request, and assert the response is 200 or a redirect. These tests confirm protection is active and that the happy path succeeds. Add them to your CI pipeline so any configuration change that accidentally disables protection is caught immediately.
โ–ถ Start Quiz