Automatically infer `OpenApiSecuritySchemes` from authentication configuration
captainsafia opened this issue · 10 comments
At the moment, when users enable authentication in their ASP.NET apps, they typically have to manually the describe the OpenApiSecuritySchemes in their application and the top level and configure OpenApiSecurityRequirements for each route that requires authentication and authorization.
We should infer as much of these definitions as possible so users don't need to configure auth twice, once for their application and another time for OpenAPI.
Provide metadata support for parts of the specification documented in https://swagger.io/docs/specification/authentication/.
Thanks for contacting us.
We're moving this issue to the .NET 7 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Who knew auth could be so hard? 🤪
I started experimenting with some of this support in the new Microsoft.AspNetCore.OpenAPI package. The problem is generally easy to solve for cookie and JWT bearer-based authentication types, but OAuth authentication types are a lot trickier for us to derive automatic annotations for because:
- We don't store any information about what type of grant flow an OAuth implementation uses
- We don't make it easy for authentication scheme providers to describe what authentication type they are
We've had conversations about how to make the authentication system more self-describing for annotation purposes. There's more design scenarios to reason about here but for .NET 7 we're scoping it down to auto-generating annotations for JWT-bearer based types to align with the work we've done with dotnet user-jwts and the options-from-config changes.
...but for .NET 7 we're scoping it down to auto-generating annotations for JWT-bearer based types...
@captainsafia wouldn't it be possible to request the information from the user for the things that are hard to imply? Not having any scaffolding for AAD integration feels really unprofessional right now (in the sense that it is a solution that just doesn't work at all out of the box) and it would be really nice to have something in place for .NET7.
Also, a lot of parameters used to build the auth schema for swagger can leverage the config section created by Azure AD itself: that's what I did for a few APIs on my side by creating a generic extension method that introduces a IConfigureOptions implementation for SwaggerGenOptions and SwaggerUIOptions that rely on the AzureAD config options to read some of the values to build things like the authorize/token URLs. The only "inputs" needed for a default scafolding would be what grant types the user expects to support (it could default to "Implicit" by default for example which is the simplest one). Even scopes are added in the config by default so even those could be inferred.
Then if the user wants to move away from some of that stuff (like handling scopes directly without the config) they can edit the initial template code to accomodate.
On another note, I wish Azure AD's OpenIdConnect endpoint was more useful for this... if it returned app-specific scopes and URLs, it could be used directly with Swagger to automatically setup a lot of different details that have to be manually added today when using the OAuth2 SecuritySchemeType.
As it stands today, AzureAD's OpenIdConnect discovery endpoint is completely useless IMHO.
Related:
@captainsafia wouldn't it be possible to request the information from the user for the things that are hard to imply?
Perhaps within reason. Although the goal of this design is to automatically generate as much of the OpenApiSecurityRequirement and OpenApiSecurityScheme definitions in the document as possible.
Also, a lot of parameters used to build the auth schema for swagger can leverage the config section created by Azure AD itself:
We had discussed this option. It dovetails nicely in some ways with the work we're doing to support loading more authentication options from config (see #42170). However, configuration isn't the source of truth for how authentication is set up in application. You'll get something that partly works for generating some schemas but not all the time. Not to mention, the approach doesn't help at all for applying the security requirements on operations.
Not having any scaffolding for AAD integration feels really unprofessional right now
We hadn't really explored doing this as part of the template/scaffolding infrastructure. At the moment, the plan is to do this work in the framework so that it can play well with all authentication strategies.
I spent some time prototyping what this would look like and landed on a pretty solid strategy that uses PostConfigureOptions on a custom AuthenticationBuilder that would work well for this.
With that in mind, here's some of the challenges:
- The
PostConfigureOptionsneeds to be added to DI as part of theAddAuthenticationcall. In my demo, I added this behavior to a customWebApplicationAuthenticationBuilderthat was part ofWebApplication. Similar to the model that we tried out in .NET 7 withbuilder.Authentication. It's not totally necessary but not having it would mean that this behavior will be enabled for all authentication scenarios in .NET 8. - The
PostConfigureOptionswould need to emitOpenApiSecuritySchemesgivenAuthenticationSchemeOptionsbut cannot take a dependency on the type since it is not in the shared framework. We could consider packaging it in the shared framework or build a set of intermediary definitions. - The prototype relies on a global document service existing (see #44192) so that the security schemes under components can be populated.
I only got CookieOptions and GoogleOptions working for the sake of my demo but we probably want to support the full spectrum of authentication options in framework. Starting a draft of the options in the table below here:
| Authentication option | Generated security requirement |
|---|---|
| JwtBearerOptions | { type: 'http', scheme: 'Bearer' } |
The PostConfigureOptions would need to emit OpenApiSecuritySchemes given AuthenticationSchemeOptions but cannot take a dependency on the type since it is not in the shared framework. We could consider packaging it in the shared framework or build a set of intermediary definitions.
I think building a set of intermediary types is the best choice here. It'll allow us to provide plugins for MVC + NSwag/Swashbuckle and will allow community-provided authentication providers to present their own definitions for the auth strategies they register. Although it increases the API surface area of the feature it is the most flexible.