First off - thanks again for the response. In digging around the interwebs (partially because it altogether wasn’t clear to me how to proceed with overwriting the auth popup page in compiled Swagger code) I discovered indications that oauth2 IS supported natively in Swagger, and proceeded to add the following configuration:
Plugins.Add(new OpenApiFeature
{
ApiDeclarationFilter = api => api.SecurityDefinitions.Add(
"bearer", new OpenApiSecuritySchema {
Type = "oauth2",
AuthorizationUrl= "https://OURAUTHSERVER/connect/authorize",
Flow="implicit",
Scopes = new Dictionary<string, string>() { { "myapi", "My API" } },
Description="oAuth2 Implicit Grant",
Name = "Authorization",
In = "header" }),
OperationFilter = (name, op) => {
if (op.Security?.Count > 0)
op.Security.Add(new Dictionary<string, List<string>>() { { "bearer", new List<string>() } }); }
});
Now, when the Authorization is clicked (the blue exclamation point button with each API) there is a popup that appears with an authorize button. When clicked, it automatically redirects to the oAuth server specified and with some fiddling (see issues below) it allows a login attempt and return back to the Swagger doc with a token that is used in the header when it attempts to call the API. I am hoping this approach can work as it is much preferred vs overwriting custom auth popup. Here are the issues that exist, I am hoping you/someone can help them to resolution such that we will have a complete guide on how to integrate ServiceStack/Swagger with oAuth2 for us and any other users.
Open Issues:
- The auth popup displays both oAuth2 as an option along with Basic Authentication. Basic should not be there - how do we make it go away? I assume this has to do with the code you suggested Adding to the Security collection.
- The scope specified in my code (myapi), is not displayed as a selectable option in the oauth2 section in the popup. Based on the Swagger documentation I have seen, it should be shown there. Because it is not shown, it is not selected and therefore the URL that gets generated and passed to the Auth server when the authenticate button is clicked is invalid as it shows scope= without any value.
- The URL generated also doesn’t insert the clientid field (instead it had clientid=your_client_id. This isn’t surprising because the configuration gave no place to specify the clientid. The fact that the URL is generated with the clientid field would imply there is some way to specify it…
- The Auth server responds with both a JWT and a reference token and the Swagger doc decided to use the reference token instead of the JWT and pass that in as the bearer token in the header. The API fails as it expects the JWT.
I believe these issues are solvable as we have Swashbuckle running on top of WebAPI in our current version. I am including below the configuration sections from that implementation in case that helps at all:
GlobalConfiguration.Configuration
.EnableSwagger(c =>
c.OAuth2("oauth2")
.Description("OAuth2 Implicit Grant")
.Flow("implicit")
.AuthorizationUrl("https://AUTHURL/connect/authorize")
.Scopes(scopes =>
{
scopes.Add("myapi", "My API");
});
c.OperationFilter<AssignOAuth2SecurityRequirements>();
})
.EnableSwaggerUi(c =>
c.EnableOAuth2Support(
clientId: "myui",
realm: "realm",
appName: "Swagger UI"
);
});
public class AssignOAuth2SecurityRequirements : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var actFilters = apiDescription.ActionDescriptor.GetFilterPipeline();
var allowsAnonymous = actFilters.Select(f => f.Instance).OfType<OverrideAuthorizationAttribute>().Any();
if (allowsAnonymous)
return; // must be an anonymous method
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{"oauth2", new List<string> {"myapi"}}
};
operation.security.Add(oAuthRequirements);
}}
Thanks in advance for whoever picks up the mantle here