6

I'm trying to add authorization header into SwaggerUI api test. below is my Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
       
        services.AddControllers();
        services.Configure<ApiBehaviorOptions>(options =>
        {
            options.SuppressModelStateInvalidFilter = true;
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Version = "v1",
                Title = "API",
                Description = "QPIN API with ASP.NET Core 3.0",
                Contact = new OpenApiContact()
                {
                    Name = "Tafsir Dadeh Zarrin",
                    Url = new Uri("http://www.tdz.co.ir")
                }
            });
            var securitySchema = new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey
            };
            c.AddSecurityDefinition("Bearer", securitySchema);
            
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securitySchema, new[] { "Bearer" });
            c.AddSecurityRequirement(securityRequirement);
            
        });
    }

    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
    {
        app.UseCors("Cors");


        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMiddleware<ApiResponseMiddleware>();
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });
        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();


        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

    }

The Authorize button has been added to the Swagger UI and I've entered the required access token as shown below

authorize swaggerUI

but the issue is when I want to try an API the token is not getting added into API request, and when I click the lock icon over the API it shows that there isn't any available authorization, see below

enter image description here

VahiD
  • 1,014
  • 1
  • 14
  • 30
  • Would be good to tell which version of Swagger (Swashbuckle) you are using. Are you getting any error in the console? You may want to check this issue https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1197 – Julien Jacobs Oct 02 '19 at 08:43
  • it's the latest version (release condidate) that I updated via package manager in VS2019 (5.0.0. rc3). when I execute an API I get an error of unauthorized , nothing else in the console – VahiD Oct 02 '19 at 09:44

4 Answers4

30

There are two points in your code:

  1. For OpenApiSecurityRequirement in OpenApiSecurityRequirement, need to set OpenApiReference
  2. Need to specify Scheme with bearer

Here is a working demo:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "API",
        Description = "QPIN API with ASP.NET Core 3.0",
        Contact = new OpenApiContact()
        {
            Name = "Tafsir Dadeh Zarrin",
            Url = new Uri("http://www.tdz.co.ir")
        }
    });
    var securitySchema = new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer",
        Reference = new OpenApiReference
        {
            Type = ReferenceType.SecurityScheme,
            Id = "Bearer"
        }
    };
    c.AddSecurityDefinition("Bearer", securitySchema);

    var securityRequirement = new OpenApiSecurityRequirement();
    securityRequirement.Add(securitySchema, new[] { "Bearer" });
    c.AddSecurityRequirement(securityRequirement);
});
Edward
  • 28,296
  • 11
  • 76
  • 121
  • 1
    Brilliant answer, thank you. I was wondering is there any way to identify which APIs need authorization, so just send the authorization header for those APIs? – VahiD Oct 03 '19 at 18:55
  • Yes, the solution is described on the [Swashbuckle.AspNetCore github](https://github.com/domaindrivendev/Swashbuckle.AspNetCore#operation-filters) – Bruno Martins Feb 21 '20 at 14:36
11

My implementation - excludes locks on non protected endpoints - with OperationFilter

internal static void SwaggerSetup(this IServiceCollection services, OpenApiInfo settings)
    {
        if (settings.Version != null)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc(settings.Version, settings);
                c.OperationFilter<AddAuthHeaderOperationFilter>();
                c.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
                {
                    Description = "`Token only!!!` - without `Bearer_` prefix",
                    Type = SecuritySchemeType.Http,
                    BearerFormat = "JWT",
                    In = ParameterLocation.Header,
                    Scheme = "bearer"
                });
            });
        }
    }

and the OperationFilter

private class AddAuthHeaderOperationFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var isAuthorized = (context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
                                && !context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any()) //this excludes controllers with AllowAnonymous attribute in case base controller has Authorize attribute
                                || (context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
                                && !context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any()); // this excludes methods with AllowAnonymous attribute

            if (!isAuthorized) return;

            operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
            operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });

            var jwtbearerScheme = new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" }
            };

            operation.Security = new List<OpenApiSecurityRequirement>
            {
                new OpenApiSecurityRequirement { [jwtbearerScheme] = new string []{} }
            };
        }
    }

Reference https://thecodebuzz.com/jwt-authorize-swagger-using-ioperationfilter-asp-net-core/

just added the condition to exclude AllowAnonymous decorated methods

Result

Kiril Kolev
  • 158
  • 1
  • 15
  • Updated the isAuthorized check to exclude controllers decorated with AllowAnnonymous attribute (in case base controller has Authorize attribute) – Kiril Kolev Jun 30 '20 at 08:19
1

Note that some parameter's type has been changed since .Net Core 3.0 as follows:

In = ParameterLocation.Header,

Type = SecuritySchemeType.ApiKey

services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey
            });
        });

Reference: https://ppolyzos.com/2017/10/30/add-jwt-bearer-authorization-to-swagger-and-asp-net-core/

Hossein POURAKBAR
  • 1,073
  • 2
  • 15
  • 33
1

In addition to what Kiril said,in my case I want to get the JWT token through Swagger and this is the code I used, adding the OpenApiSecurityScheme to what he suggested:

c.AddSecurityDefinition("bearer",
                    new OpenApiSecurityScheme{
                        Flows = new OpenApiOAuthFlows()
                        {
                            ClientCredentials = new OpenApiOAuthFlow()
                            {
                                TokenUrl = new Uri("https://auth.myauthserver.com/oauth2/token"),
                                Scopes = new Dictionary<string, string>(){ {"myscope", "Access API"}},
                                AuthorizationUrl = new Uri("https://auth.myauthserver.com/oauth2/authorize")
                            }
                        }, 
                        Type = SecuritySchemeType.OAuth2,
                        OpenIdConnectUrl = new Uri("https://myauthserver/.well-known/openid-configuration"),
                        BearerFormat = "JWT",
                        In = ParameterLocation.Header,
                        Scheme = "bearer"
                    });