Open karlschriek opened 5 months ago
Hey,
Since OpenIddict fundamentally uses the AspNet identity classes, and extends them with entities such as Appplication, Token etc. we hoped that this would be simple to do (even if for someone who is not intimately familiar with either framework).
To clarify, while OpenIddict uses an approach similar to Identity for its persistence story (entities, stores), it actually doesn't depend on Identity at all (and doesn't use it).
Would you be able to help us get this sample working correctly?
I'll give the sample a try later today but here's what I think is happening:
All the antiforgery tokens - form tokens and cookie tokens - produced by the antiforgery stack are bound to the user identity present when creating them. It's an important security aspect of this feature, tho' it's not new in ASP.NET Core (it was already supported by the ASP.NET 4.x anti-XSRF web helper). Concretely, if a page is rendered with a form antiforgery token generated for "user 1" (with a corresponding cookie token present in the Set-Cookie
response header), you'll get an error if you try to submit the form as-is if the user identity changed between the moment the form was generated and the moment you're submitting it.
Your antiforgery middleware (app.UseAntiforgery()
) is not registered at the right place (i.e it's registered before app.UseAuthentication()
), so the user identity may not be properly extracted by the time its validation logic runs. On the other hand, when Blazor asks IAntiforgeryService
to generate the antiforgery tokens, the user identity is available (since it executes much later in the pipeline), so you eventually get a mismatch when validating the tokens.
TL;DR, try to move app.UseAntiforgery()
after app.UseAuthorization()
to see if it helps.
Thanks for the clarification on OpenIddict's use of "Identity", I will definitely keep that in mind.
Also... that fix was much simpler than I expected the answer to be! You are absolutely right, placing app.UseAntiforgery()
after app.UseAuthorization()
fixes it. (The biggest tragedy of all this is that is that I had misread an error message that actually told me this a few days ago; I went back and recreated it just now and there it was in black and white)
By the way, if you find the sample useful I can also prepare it for this repo. Our full sample is actually a bit more extensive though, and consists of three services:
Basically in our use case OpenIddict acts as a central authorization service within a microservices ecosystem. It controls login into various potential client-facing applications, which also call various different downstream WebApis on behalf of the user (using access token).
Let me know if you would be interested in such a sample.
Confirm you've already contributed to this project or that you sponsor it
Version
5.4.0
Question
Background
We are currently working on using the latest .NET identity web UI (which you can get bundled in your IDE when you create a .NET 8 Blazor Web App) in combination with OpenIddict.
The latest template provides a good base for creating a production-ready UI for users to interact with the IdP, including doing things like registering MFA devices, resetting passwords, confirming email addresses and a whole lot more. (You can read more about it here https://devblogs.microsoft.com/dotnet/whats-new-with-identity-in-dotnet-8/#the-blazor-identity-ui)
Our goal was to take this template as a starting point and then integrate OpenIddict into it. Since OpenIddict fundamentally uses the AspNet identity classes, and extends them with entities such as Appplication, Token etc. we hoped that this would be simple to do (even if for someone who is not intimately familiar with either framework). To a large extent this is true, and the result of that is a sample that can be found here:
https://github.com/karlschriek/openiddict-blazor-server-sample/tree/main/OpenIddict.Blazor.Server
(For comparison, here is what the vanilla identity UI we worked from looks like: https://github.com/karlschriek/openiddict-blazor-server-sample/tree/main/VanillaIdentityUI.Blazor.Server)
In addition to the above, this sample also includes a few other things that we have worked on in the past, but these are not directly relevant to this issue
Where we need help
While we were able to get the login flows to work correctly, we are having trouble with the anti-forgery token (although I suspect this might rather just be a symptom of something more fundamental that is misconfigured). The identity UI has several places where it uses the anti-forgery token. The simplest one to test against is the "logout" button.
The moment you navigate to https://localhost:7143/ (where the "OpenIddict.Blazor.Server" sample project is hosted) I can see the anti-forgery token being set, with a name like ".AspNetCore.Antiforgery.hLXdGIjSYB8". As soon as the user logs in, the ".AspNetCore.Identity.Application" cookie is also set. If I now logout, I get:
Similar errors occur on other Blazor components that also require
<AntiforgeryToken/>
.This makes me think that either something that we switched off (such as the ".AddIdentityCookies();" extension, which causes an error if use in conjunction with the OpenIddict setup we've added) or some other fundamental mismatch is happening. Would you be able to help us get this sample working correctly? It would go a long way to us being able to take OpenIddict into production.