Before starting I assume you’ve already got OAuth2 setup correctly on your application (using bearer tokens), and you have decorated your controllers and actions with [Authorize] attributes. If you haven’t, that is beyond the scope of this blog post. Here all I’m doing is explaining how to configure Swashbuckle.
services.AddSwaggerGen(options =>
options.AddSecurityDefinition("oauth2", new ApiKeyScheme
Description = "Standard Authorization header using the Bearer scheme. Example: \"bearer {token}\"",
In = "header",
Name = "Authorization",
Type = "apiKey"
This adds a securityDefinition to the bottom of the Swagger document, which Swagger-UI renders as an “Authorize” button:
The next thing we need to do is tell Swashbuckle which of our actions require Authorization. To do that you can use the SecurityRequirementsOperationFilter:
services.AddSwaggerGen(options =>
options.AddSecurityDefinition("oauth2", new ApiKeyScheme
Description = "Standard Authorization header using the Bearer scheme. Example: \"bearer {token}\"",
In = "header",
Name = "Authorization",
Type = "apiKey"
options.OperationFilter<SecurityRequirementsOperationFilter>();
The SecurityRequirementsOperationFilter adds a security property to each operation in the Swagger document, which renders in Swagger-UI as a padlock next to the operation:
Once you’ve done that, when you “Try it out” using the Swagger-UI, the authorization header with your bearer token should be sent to your API.
Related
I am getting “Fetch error Internal Server Error v1/swagger.json” after adding options.OperationFilter(); Is there anything special that needs to be added anywhere else in the application? Do you perhaps have a working example project?
Yes, see my Github repos for a working example. .Net Core version here
https://github.com/mattfrear/Swashbuckle.AspNetCore.Filters/blob/master/test/WebApi2.0/Startup.cs
In my case , I need to store the bearer token returned after authenication(oAuth) and then pass on the same for further requests from Swagger UI. Any Ideas on how to store and process the bearer token, I have already followed all steps mentioned on your blog post
I don’t understand your question, sorry.
Where does the bearer token come from? Normally in web apis the bearer token will come from an external identity system.
Where do you want to store the bearer token? In swagger-ui somewhere? The swagger-ui javascript can be customised via Swashbuckle, but I’m not sure if that will help you.
Thanks! This really helped me get started with implementing authorization into our existing REST API.
Hello Matt,
I end up on your post while looking for a solution to what I’m trying to sort out which I believe it’s similar but not precisely the same:
On my back end, I haven’t implemented or used OAuth2. It’s not what I’m interested into right now but I want to make my clients send a key to the back-end as a sort of security mechanism. It’s still in development phase.
I just need to be able to send a key-value pair on the headers with the Swagger interface, as I would do it with Postman for instance. How can I achieve this?
Hi Sebastian, yes, that can be done, I’ve already written a Swashbuckle filter which will do that for you.
Are you using ASP.NET Core? Check out my Swashbuckle.AspNetcore.Filters package on GitHub. Or Swashbuckle.Examples if you’re using .NET Framework. See the “Add a request header” section of the readme.
https://github.com/mattfrear/Swashbuckle.AspNetCore.Filters/blob/master/README.md#add-a-request-header
Thanks a lot for your help. Now, it works perfectly fine :)
Yes, I’m developing on ASP.NET Core. I have a very simple Middleware that now is able to check that a Key is being sent. In the future, I might add OAuth2 but for the current phase, this is just fine.
Is there a way to add a “default’ value to the “value” textbox in the authorization popup?
Cool article, could you explain how this would work in a non core solution? (.net web api)
I haven’t tried it, but the steps should be the very similar.
Except you will need to copy the SecurityRequirementsOperationFilter from here
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs
and add it to your solution. You will need to convert it from a Swashbuckle.AspNetCore filter to a Swashbuckle filter (which is very easy and should only take a few minutes – just get it to compile and it should work).
Hi, great article!!!
Do you know how can I get the token first? On my web api I need to acces
http://mysite/token
passing username, password and grant_type. Then I receive the token, and this token should be passed in all requests. Is there a way to do that?
Thankz!
Yes, you need to pass a header with the key “Authorization” and value “Bearer abcd” but replace abcd with your token
I am trying to do this, but in asp.net (full framework, not core), and I just don’t find any of the above code. Are there any examples in non .net core on how to do this as well?
Cheers!
I haven’t tried it, but I think the steps should be very similar.
You will additionally need to download the SecurityRequirementsOperationFilter from here
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs
and port it to Swashbuckle 5 (i.e. not Swashbuckle.AspNetCore) which shouldn’t be too difficult. Once you have ported it, if you are feeling generous you could add it to my Swashbuckle.Examples NuGet package, via a pull request here
https://github.com/mattfrear/Swashbuckle.Examples
I’ve been trying to get this to work for 2 days now. I cannot get “BASIC” authentication working. We want to use “BASIC” when doing testing integration. Any ideas why BASIC won’t work?
Basic authentication is different, and you probably won’t need my library to do it.
Try this
services.AddSwaggerGen(c =>
c.AddSecurityDefinition(“basic”, new ApiKeyScheme
Description = “Basic Authorization using username and password”,
Type = “basic”
c.AddSecurityRequirement(new Dictionary<string, IEnumerable>
{ “basic”, Enumerable.Empty() }
No, that doesn’t work either. It seems as if Swagger just doesn’t work with authentication at all? I am using AspNetCore 2.2 project.
This didn’t work either:
c.OperationFilter();
c.AddSecurityDefinition(“BASIC”, new BasicAuthScheme() { Type = “BASIC” });
c.OperationFilter();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
c.AddSecurityDefinition(“BASIC”, new BasicAuthScheme() { Type = “BASIC” });
c.OperationFilter<SecurityRequirementsOperationFilter>();
@Tim I can’t help you I’m sorry. The code snippet I posted for you above works for me, we are using basic auth at work so I copied it from a working solution.
All swagger does is document what your API does, it does not do the basic authentication for you (if that’s what you’re thinking). Here at work we are using the Bazinga.AspNetCore.Authentication.Basic NuGet package to do the basic authentication.
Hi Matt, no problem. I find it odd that BASIC auth works fine for me from Postman, just not Swagger. I can see through Fiddler that none of the auth headers are being sent back, but other headers are (ex. pageSize, pageNumber, etc.) for some methods. May I ask what else you’ve enabled besides just the standard auth pipelines (ex. services.AddAuthentication(…), app.UseAuthentication(), etc.)?
Tim – I have a whole bunch of other stuff enabled but the code I posted above is all that you should need for basic auth. Do you see a padlock next to your actions as per the screenshots in my blog post? When you click the padlock, do you get a username and password prompt?
I finally figured it out. It dawned on me that the “app.UseAuthorization” was being called AFTER enabling swagger, this needed to be before it.
: Configure :
app.UseHttpsRedirection();
this.ConfigureAuthentication(app, env);
this.ConfigureSwagger(app, env);
app.UseMvc();
@mattfrear
Great article.
I have been trying to find a solution to the final piece of the puzzle. I have an Authorization Button in the header with a password flow for oAuth2. If I fill in and submit I get my oAuth2 token back from the server.
I have decorated my operations with the [Authorize] attribute rather than SecurityRequirementsOperationFilter partly as I want to get just one working for now.
The issue which remains is – even after you authorize, the Authorization: {token} header is not being attacked.
What do you think that might be?
Excellent article, thanks.
Worth mentioning a problem I came across when I’ve implemented your code, I’ve received this error when I tried loading swagger:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.ArgumentException: An item with the same key has already been added. Key: 401
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at Swashbuckle.AspNetCore.Filters.SecurityRequirementsOperationFilter`1.Apply(Operation operation, OperationFilterContext context)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreateOperation(ApiDescription apiDescription, ISchemaRegistry schemaRegistry)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreatePathItem(IEnumerable`1 ntext)
The problem is SecurityRequirementsOperationFilter automatically adds 401 and 403 return values, which I added to the documentation manually. To avoid adding it twice, you should change
options.OperationFilter();
options.OperationFilter(false);
as described here:
https://github.com/mattfrear/Swashbuckle.AspNetCore.Filters/blob/master/README.md#how-to-use—security-requirements-filter
Thanks again.
Thanks, yeah that bug is already fixed in the latest rc version of my Swashbuckle.AspNetCore.Filters package.
Very nicely written article. Works with Swagger, I got everything as expected. However, whenever I make a request to one of the methods marked with the Authorize attribute I get back status 500 and an exception that says “No authenticationScheme was specified, and there was no DefaultChallengeScheme found.” The method is not executing, of course. I could not figure out why this is happening. Any ideas?
Hi Marius. I don’t know sorry – what happens when you hit your API via Postman? Does it return the same error? If it does it’s probably a problem with your authentication setup rather than with Swashbuckle.
Hi, I wanted to know if it was possible to implement the “Authorize” button in ASP.NET framwerk??.
Yes. If you’re on .NET Framework then you’ll need to use the old version of Swashbuckle.
See the instructions here:
https://github.com/domaindrivendev/Swashbuckle#describing-securityauthorization-schemes
PS. I am not the author of Swashbuckle so I cannot help you if you can’t get it to work.
When navigating to the OpenApi landing page, the service is authorized, and an authorization header added to the Request Headers. However, I would then like to send this authorization header with each Swagger request but it’s not being sent?
Ideally I would like to show the Authorize Button to be pre-authorised (so I don’t need to enter any credentials), if a authorization header already exists?
Hi Mark
I think I know what you mean. Unfortunately I haven’t worked with OAuth for a few years, so I don’t know how to do that.
Hi Matt,
I don’t think it’s an OAuth issue? Navigating to our service requires basic authorization, with this header being included in the Swagger Landing Page when viewing in index.html request. I would then like to sent this authorization header with each Swagger request on the page, rather than explicitly re-entering the credentials again via the Authorize button.
I’m currently investigating whether custom javascript or pre-authorization is the way forward?
This worked OK when using .Net Core 2.2, so possibly OpenAPI is stripping the authorization header since moving to .Net Core 3.1?
I’m curious to know how you locked down the Swagger page with basic auth? And how are the credentials entered – does the browser just pop up a username and password dialog box?
When you say it was working with .NET Core 2.2, were you also using Swagger 2.0, and are you now using OpenApi 3?
If so, it’s a long shot, but you could try telling Swashbuckle to output Swagger 2.0 via
app.UseSwagger(c =>
c.SerializeAsV2 = true;
But I’m out of ideas. You could try ask the author of Swashbuckle.AspNetCore over at
https://github.com/domaindrivendev/Swashbuckle.AspNetCore
.
Yes, the browser shows a pop-up when navigating to the page, and yes we were using Swagger 2.0 and now OpenApi 3.
Tried adding SerializeAsV2. Good suggestion. I now see the authorization header, but no value.
I’ll raise with Swashbuckle.AspNetCore author. Cheers.
How to implement this with custom authorization filter class that implement Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter in .net core 5?
Hi Ivan,
If your filter is applied to every endpoint (i.e. causes all of your endpoints to have Authorization), then you can tell Swashbuckle that with AddSecurityRequirement().
If however your custom filter only applies Authentication to some of your endpoints, then you’re gonna need to write a custom Swashbuckle IOperationFilter of your own.
See the documentation here:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore#add-security-definitions-and-requirements
Hello, is that possible to reach till “Authorize” button click event? I want to restrict users at this point before they actually execute any request?
Yes, I think it is possible, although I haven’t done it.
https://github.com/domaindrivendev/Swashbuckle.AspNetCore#apply-swagger-ui-parameters
Swagger supports adding a Header parameter for 1 method
for example:
method with attribute [Authorize(“AtLeast21”)]
builder.Services.AddAuthorization(options =>
options.AddPolicy(“AtLeast21”, policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
and i want to add new header parameter to swagger only for method with this attribute
public class AddRequiredHeaders : IOperationFilter
public void Apply(OpenApiOperation operation, OperationFilterContext context)
if (context.MethodInfo.DeclaringType?.Name == nameof(ExportController))
return;
operation.Parameters ??= new List();
operation.Parameters.Add(
new OpenApiParameter
Name = “CustomHeadersNames”,
In = ParameterLocation.Header,
Required = true,
Schema = new OpenApiSchema { Type = “string” }
this case add to all api method parameter, but i want add only for method with this attribute.
how to do this?