Skip to content

Don't apply the CSRF verdict to remote authentication callbacks - #68669

Merged
wtgodbe merged 2 commits into
dotnet:release/11.0-rc1from
DeagleGross:deaglegross-scaling-bassoon
Aug 21, 2026
Merged

Don't apply the CSRF verdict to remote authentication callbacks#68669
wtgodbe merged 2 commits into
dotnet:release/11.0-rc1from
DeagleGross:deaglegross-scaling-bassoon

Conversation

@DeagleGross

Copy link
Copy Markdown
Member

Fixes #68666.

A Blazor Web App using AddOpenIdConnect fails the sign-in callback with InvalidOperationException: This form is being accessed with a failed antiforgery validation thrown from FormFeature.ReadFormAsync, inside OpenIdConnectHandler.HandleRemoteAuthenticateAsync.

How this worked in .NET 10 with antiforgery

Token antiforgery is per-endpoint: AntiforgeryMiddleware only validates when the matched endpoint carries IAntiforgeryMetadata with RequiresValidation: true, which Blazor attaches to each routable component endpoint in RazorComponentEndpointFactory. /signin-oidc is not a component endpoint, so it never carried that metadata. More importantly, UseAntiforgery() sits after UseAuthentication(), and RemoteAuthenticationHandler short-circuits the callback as an IAuthenticationRequestHandler — so the antiforgery middleware never ran for the callback at all.

Why CSRF protection triggers now

CsrfProtectionMiddleware is auto-injected and runs in the post-routing pipeline, which EndpointRoutingMiddleware invokes immediately after matching — i.e. before UseAuthentication(), so the auth handler no longer short-circuits ahead of it. It records IAntiforgeryValidationFeature { IsValid = false } plus an HttpContext.Items marker instead of rejecting the request (#67082), deferring the failure to whoever reads the body. For the callback that consumer is the OIDC handler itself, and it reads the form before OnMessageReceived fires, so applications have no way to opt out.

Why the callback is always a cross-site request

With response_mode=form_post the identity provider returns the response as a top-level auto-submitted form POST from its own origin to CallbackPath, so the browser always sends Sec-Fetch-Site: cross-site. That is the exact shape the Fetch Metadata algorithm classifies as a CSRF attempt, and nothing about a legitimate callback distinguishes it at the HTTP layer. form_post is the default for response_type values containing id_token and is what Entra ID and Microsoft.Identity.Web use, so this fails deterministically rather than intermittently. The same applies to WS-Federation and to the OIDC RemoteSignOutPath.

Why suppressing the verdict here is safe

The callback carries its own forgery protection: state round-trips a data-protected AuthenticationProperties payload whose correlation id must match the .AspNetCore.Correlation.* cookie, and ValidateCorrelationId rejects the request when it doesn't. Nonce validation for id_token and PKCE for the code flow apply on top of that, none of which an attacker can forge. The verdict is suppressed only while the handler owns the request and is restored when it declines (SkipHandler / SkipUnrecognizedRequests / exception), so anything the handler hands back to the pipeline still sees the original verdict.

A remote provider's callback (OIDC response_mode=form_post, WS-Federation)
is a cross-site form POST by protocol design, so the auto-injected CSRF
protection records an invalid IAntiforgeryValidationFeature verdict for it.
The handler then throws while reading its own callback body, before any of
its events can run, so apps have no way to opt out.

Suppress the verdict while a remote handler owns the request, and restore it
if the handler declines so the rest of the pipeline still sees it.

Fixes dotnet#68666

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb987098-3301-465b-9a3d-2e63aabf43bd
@DeagleGross DeagleGross self-assigned this Aug 20, 2026
@DeagleGross
DeagleGross requested a review from javiercn August 20, 2026 18:15
@DeagleGross
DeagleGross marked this pull request as ready for review August 21, 2026 07:57
Copilot AI lite review requested due to automatic review settings August 21, 2026 07:57
@DeagleGross DeagleGross added area-identity Includes: Identity and providers feature-antiforgery labels Aug 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression where automatic cross-origin CSRF protection records an invalid IAntiforgeryValidationFeature on remote authentication callback requests (e.g., OIDC response_mode=form_post), causing ReadFormAsync to throw before the authentication handler can process the callback.

Changes:

  • Introduces a shared helper to temporarily suppress an invalid antiforgery/CSRF verdict while a remote authentication handler processes its owned callback request, restoring it if the handler declines.
  • Applies the suppression in RemoteAuthenticationHandler (covers standard remote callbacks) and in OpenIdConnectHandler for its additional callback endpoints.
  • Adds integration tests validating that cross-site callback POSTs can be read by the handler, and that the invalid verdict is restored when the handler skips the request.
Show a summary per file
File Description
src/Shared/RemoteAuthenticationAntiforgery.cs Adds shared helper to suppress/restore invalid IAntiforgeryValidationFeature during remote handler execution.
src/Security/Authentication/Core/src/RemoteAuthenticationHandler.cs Wraps callback handling in the suppression helper (covers CallbackPath).
src/Security/Authentication/Core/src/Microsoft.AspNetCore.Authentication.csproj Links the new shared helper into the authentication core build.
src/Security/Authentication/OpenIdConnect/src/OpenIdConnectHandler.cs Uses the helper for OIDC-specific callback paths that can read form_post bodies.
src/Security/Authentication/OpenIdConnect/src/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj Links the new shared helper into the OpenIdConnect build.
src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/RemoteAuthenticationCsrfTests.cs Adds tests proving the handler can read cross-site callback forms and that downstream protection is preserved when skipping.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 6/6 changed files
  • Comments generated: 0
  • Review effort level: Lite

@wtgodbe
wtgodbe merged commit 558ba2c into dotnet:release/11.0-rc1 Aug 21, 2026
41 of 45 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc1 milestone Aug 21, 2026
wtgodbe added a commit that referenced this pull request Aug 22, 2026
* [SignalR] Reject duplicate SignalR upload stream IDs (#68525) (#68638)

* Reject duplicate SignalR upload stream IDs



* Simplify upload stream ownership cleanup



* Avoid upload stream ownership allocations



* Simplify upload stream registration ownership



* Defer upload stream reader creation





* Dispose cancellation source after binding failure





* Reuse upload stream test helper





---------

Co-authored-by: Javier Calvarro Nelson <jacalvar@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 82e97f5a-a052-4dbe-9cf1-b62f45cf7ee2

* Honor all sign-in confirmation requirements after registration (#68631) (#68655)

Co-authored-by: Brennan <brecon@microsoft.com>

* Preserve BadHttpRequestException status codes (#68632) (#68649)

* Preserve BadHttpRequestException status codes



* Preserve exception handler 404 safeguard



---------

Co-authored-by: Stephen Halter <halter73@gmail.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* SignInManager: return SignInResult.Failed for expired passkey session challenge (#67539) (#68654)

Co-authored-by: Grant Totinov <granttotinov604@gmail.com>

* Don't apply the CSRF verdict to remote authentication callbacks (#68669)

* Don't apply the CSRF verdict to remote authentication callbacks

A remote provider's callback (OIDC response_mode=form_post, WS-Federation)
is a cross-site form POST by protocol design, so the auto-injected CSRF
protection records an invalid IAntiforgeryValidationFeature verdict for it.
The handler then throws while reading its own callback body, before any of
its events can run, so apps have no way to opt out.

Suppress the verdict while a remote handler owns the request, and restore it
if the handler declines so the rest of the pipeline still sees it.

Fixes #68666

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb987098-3301-465b-9a3d-2e63aabf43bd

* test both antiforgery & csrf

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb987098-3301-465b-9a3d-2e63aabf43bd

* Use model display names in Blazor input parsing errors (#68667) (#68688)

* Use display attributes in input parsing errors

* Address test coverage feedback from review.

* Apply dedup cleanup from feedback.

Co-authored-by: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com>

* [release/11.0-rc1] Extract IsAuthenticated helper method (#68658)

* Extract IsAuthenticated helper method

Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>

* Reorder using

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>

* Use SecurityHelper for authentication revalidation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>

---------

Co-authored-by: Youssef1313 <youssefvictor00@gmail.com>
Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>
Co-authored-by: Milos Kotlar <kotlarmilos@gmail.com>

* Fix  InitialItemIndex viewport underfill for small items in big container or on window resize (#67936) (#68689)

Co-authored-by: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com>

* fix nullable<union> for openapi gen (#68665)

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Javier Calvarro Nelson <jacalvar@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Brennan <brecon@microsoft.com>
Co-authored-by: Stephen Halter <halter73@gmail.com>
Co-authored-by: Grant Totinov <granttotinov604@gmail.com>
Co-authored-by: Korolev Dmitry <dmkorolev@microsoft.com>
Co-authored-by: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Youssef1313 <youssefvictor00@gmail.com>
Co-authored-by: Youssef1313 <31348972+Youssef1313@users.noreply.github.com>
Co-authored-by: Milos Kotlar <kotlarmilos@gmail.com>
Co-authored-by: William Godbe <wigodbe@microsoft.com>
Copilot-Session: 82e97f5a-a052-4dbe-9cf1-b62f45cf7ee2
Copilot-Session: cb987098-3301-465b-9a3d-2e63aabf43bd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-identity Includes: Identity and providers feature-antiforgery

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants