I use tokens generated by an authentication service for my app. No problems there. Now I have introduced Swashbuckle to document my API an I can authenticate as follows by s
Swagger would add the authorzation header if you specified the filter on your methods. If you globally require authorization my guess is that swagger doesn't recognize them.
You need to add a SecurityRequirement like this in your ConfigureServices:
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>()
{
{ "Bearer", new string[]{ } }
});
This will require the header to be sent with every request if the token is set. If you didn't set the header before it'll not send it, but you'll still have the padlock sign next to your api description.
If you define in code
c.AddSecurityDefinition("jwt", new ApiKeyScheme()
{
In = "header", Description = "Please insert JWT with Bearer into field", Name = "Authorization", Type = "apiKey" });
and then use it in not in .Parameters, but in .Security
operation.Security = new List<IDictionary<string, IEnumerable<string>>> {
new Dictionary<string, IEnumerable<string>>
{
{"jwt", _scopes }
}
then everything should work:
I do the same as you do, but you should add like follows (for oauth2 or jwt bearer token auth):
public static class ServiceCollectionExtension
{
private static string XmlCommentsFilePath
{
get
{
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var fileName = Assembly.GetEntryAssembly().GetName().Name + ".xml";
return Path.Combine(basePath, fileName);
}
}
public static void AddMySwagger(
this IServiceCollection services,
ApiVersion defaultApiVersion,
Func<ApiVersionDescription, Info> info,
string authority = null,
Dictionary<string, string> scopes = null)
{
services.AddMvcCore().AddVersionedApiExplorer(o => o.GroupNameFormat = "'v'VVV");
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = defaultApiVersion;
});
services.AddSwaggerGen(
options =>
{
var provider = services.BuildServiceProvider()
.GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
if (!description.IsDeprecated)
options.SwaggerDoc(description.GroupName, info(description));
}
options.OperationFilter<DefaultValues>();
options.IncludeXmlComments(XmlCommentsFilePath);
if (!string.IsNullOrEmpty(authority))
{
options.AddSecurityDefinition("jwt", new ApiKeyScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
Name = "Authorization",
In = "header",
Type = "apiKey"
});
//options.AddSecurityDefinition("oauth2", new OAuth2Scheme
//{
// Flow = "implicit",
// AuthorizationUrl = $"{authority}/connect/authorize",
// Scopes = scopes ?? new Dictionary<string, string>()
//});
options.OperationFilter<AuthorizeCheckOperationFilter>(scopes?.Select(_ => _.Key).ToList() ?? new List<string>());
}
});
}
class AuthorizeCheckOperationFilter : IOperationFilter
{
private readonly IEnumerable<string> _scopes;
public AuthorizeCheckOperationFilter(IEnumerable<string> scopes)
{
_scopes = scopes;
}
public void Apply(Operation operation, OperationFilterContext context)
{
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
if (hasAuthorize)
{
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
operation.Responses.Add("403", new Response { Description = "Forbidden" });
operation.Security = new List<IDictionary<string, IEnumerable<string>>> {
new Dictionary<string, IEnumerable<string>>
{
//{"oauth2", _scopes},
{"jwt", _scopes }
}
};
}
}
}
}
Usage:
services.AddMySwagger(
new ApiVersion(1, 0),
__description => new Info { Title = $"API v{__description.ApiVersion}", Version = __description.ApiVersion.ToString() },
Configuration.GetValue<string>("Authentication:Authority"),
new Dictionary<string, string> { { Configuration.GetValue<string>("Authentication:Scope"), "Partnership API" } }
);
In the end I moved to NSwag so I am not sure what the original issue was. The solution in Nswag is as follows;
services.AddSwaggerDocument(document =>
{
document.DocumentName = "CPSwagger";
document.Title = "My Mobile API";
document.Version = "v10.3.4";
document.Description = "An interface for some software.";
document.DocumentProcessors.Add(
new SecurityDefinitionAppender("JWT token", new NSwag.OpenApiSecurityScheme
{
Type = NSwag.OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = NSwag.OpenApiSecurityApiKeyLocation.Header
}));
document.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token"));
});