I have an ASP.NET Core Web API with Swagger integrated using Swashbuckle. I have successfully integrated authorization on Swagger UI using an operation filter, because I do not want to show padlock for anonymous APIs.
.OperationFilter<AuthorizeFilter>()
Inside the filter, I have registered basic auth security requirement for Swagger UI.
My problem is, even though authentication is happening in APIs on Swagger UI, I no longer see that nice authentication popup which is giving when click on the padlock icon.
Could someone answer, why I am not seeing the auth popup now?
Update 2023-04-17: Updated security definition type to Http
as per @mimmoz81's suggestion
Assuming you have some endpoints that protected with [Authorize]
attribute (can also be put on the controller).
[Route("")]
public class HelloController : ControllerBase
{
[Authorize]
[HttpGet("secure")]
public IActionResult GetSomethingPrivate()
{
return Ok("secret");
}
[HttpGet("public")]
public IActionResult GetSomethingPublic()
{
return Ok("hey");
}
}
You need to define a security scheme suitable for your needs. But do not require it globally, instead add it inside an operation filter. Here I've added a simple token auth:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ApiPlayground", Version = "v1" });
c.AddSecurityDefinition("token", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
In = ParameterLocation.Header,
Name = HeaderNames.Authorization,
Scheme = "Bearer"
});
// dont add global security requirement
// c.AddSecurityRequirement(/*...*/);
c.OperationFilter<SecureEndpointAuthRequirementFilter>();
});
}
And here's the operation filter which references the token
auth scheme we've just created. It checks if the endpoint needs authentication, then adds the requirement.
internal class SecureEndpointAuthRequirementFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (!context.ApiDescription
.ActionDescriptor
.EndpointMetadata
.OfType<AuthorizeAttribute>()
.Any())
{
return;
}
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "token" }
}] = new List<string>()
}
};
}
}
When you run the app, it works as you expect:
So does the auth popup:
Define a new security scheme with following values:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddSwaggerGen(c =>
{
// ...
// basic auth scheme (username + password)
c.AddSecurityDefinition("basic", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "basic"
});
// dont add global security requirement
// c.AddSecurityRequirement(/*...*/);
c.OperationFilter<SecureEndpointAuthRequirementFilter>();
});
}
Then update the operation filter to reference basic
auth scheme:
internal class SecureEndpointAuthRequirementFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (!context.ApiDescription
.ActionDescriptor
.EndpointMetadata
.OfType<AuthorizeAttribute>()
.Any())
{
return;
}
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "basic" // <-- changed "token" -> "basic"
}
}] = new List<string>()
}
};
}
}
here's how the auth popup looks:
After logging in, requests include the correct Authorization
header.