Swagger UI - authentication only for some endpoints
Asked Answered
P

2

6

I am using Swagger in a .NET COre API project. Is there a way to apply JWT Authentication in Swagger UI only for some endpoints?

I put [Authorize] Attribute only on a few calls (also have tried putting [AllowAnonymous] on the calls that don't need authentication), but when I open the Swagger UI page, the lock symbol is on all the endpoints.

Procryptic answered 3/12, 2019 at 13:35 Comment(0)
W
6

You'll have to create an IOperationFilter to only add the OpenApiSecurityScheme to certain endpoints. How this can be done is described in this blog post (adjusted for .NET Core 3.1, from a comment in the same blog post).

In my case, all endpoints defaults to [Authorize] if not [AllowAnonymous] is explicitly added (also described in the linked blog post). I then create the following implementation of IOperationFilter:

public class SecurityRequirementsOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (!context.MethodInfo.GetCustomAttributes(true).Any(x => x is AllowAnonymousAttribute) &&
            !(context.MethodInfo.DeclaringType?.GetCustomAttributes(true).Any(x => x is AllowAnonymousAttribute) ?? false))
        {
            operation.Security = new List<OpenApiSecurityRequirement>
            {
                new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme {
                            Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "bearer"
                            }
                        }, new string[] { }
                    }
                }
            };
        }
    }
}

You'll have to tweak the if statement if you don't default all endpoints to [Authorize].

Finally, where I call services.AddSwaggerGen(options => { ... } (usually in Startup.cs) I have the following line:

options.OperationFilter<SecurityRequirementsOperationFilter>();

Note that the above line will replace the (presumably) existing call to options.AddSecurityRequirement(...) in the same place.

Whinchat answered 26/4, 2020 at 6:51 Comment(1)
This was really helpful! I had to use Id = "Bearer" to match my code in Startup.cs: c.AddSecurityDefinition("Bearer", ...Duer
Q
0

Here is the best solution, if you use [Authorize] attribute:

public static class SwaggerAuthExtension
    {
        private static readonly string authType = "Bearer JWT";

        private static readonly OpenApiSecurityRequirement requirement = new()
        {{
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = authType
                }
            },
            new string[]{}
        }};

        private static readonly OpenApiSecurityScheme scheme = new()
        {
            In = ParameterLocation.Header,
            Description = "Please enter a valid token",
            Name = "Authorization",
            Type = SecuritySchemeType.Http,
            BearerFormat = "JWT",
            Scheme = "Bearer"
        };

        public static void AddJWTAuth(this SwaggerGenOptions option)
        {
            option.AddSecurityDefinition(authType, scheme);
            option.OperationFilter<SecurityRequirementsOperationFilter>();
        }

        public static void AddSwaggerGenWithJWTAuth(this IServiceCollection services)
        {
            services.AddSwaggerGen(opt => opt.AddJWTAuth());
        }

        private class SecurityRequirementsOperationFilter : IOperationFilter
        {
            public void Apply(OpenApiOperation operation, OperationFilterContext context)
            {
                if (
                    context.MethodInfo.GetCustomAttributes(true).Any(x => x is AuthorizeAttribute) ||
                    (context.MethodInfo.DeclaringType?.GetCustomAttributes(true).Any(x => x is AuthorizeAttribute) ?? false)
                )
                {
                    operation.Security = new List<OpenApiSecurityRequirement>
                    {
                        requirement
                    };
                }
            }
        }
    }

Usage:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSwaggerGenWithJWTAuth();

or

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSwaggerGen(opt => opt.AddJWTAuth());

Based on Julian's answer. I changed the if statement in SecurityRequirementsOperationFilter class for searching for AuthorizeAttribute.

Quennie answered 10/11, 2023 at 15:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.