What if we do not want to open our OpenAPI schema to the world? We can choose some paths:

  • basic authorization
  • OpenId Connect authorization using identity server

In this article, I am going to show the second path.

Default tools

First of all, I tried to configure OAuth 2 authorization with integrated tools of swagger UI:

namespace App
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services
                .AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
                {
                    options.Authority = "https://demo.identityserver.io/";
                    options.TokenValidationParameters.ValidateAudience = false;
                });

            // Add OpenAPI/Swagger document
            services.AddOpenApiDocument(configure =>
            {
                configure.SchemaNameGenerator = new CustomSchemaNameGenerator();
                configure.TypeNameGenerator = new CustomTypeNameGenerator();
                configure.PostProcess = document =>
                {
                    document.Info.Version = "v1";
                    document.Info.Title = "App API";
                    document.Info.Description = "A simple ASP.NET Core web API";
                    document.Info.TermsOfService = "None";
                    document.Info.Contact = new OpenApiContact
                    {
                        Name = "Renat Sungatullin",
                        Email = string.Empty,
                        Url = "https://medium.com/dev-genius/nswag-csharp-client-with-generics-support-6ad6a09f81d6"
                    };
                };

                configure.AddSecurity("bearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme
                {
                    Type = OpenApiSecuritySchemeType.OAuth2,
                    Flows = new OpenApiOAuthFlows()
                    {
                        AuthorizationCode = new OpenApiOAuthFlow()
                        {
                            Scopes = new Dictionary<string, string>
                            {
                                { "api", "" },
                            },
                            AuthorizationUrl = "https://demo.identityserver.io/connect/authorize",
                            TokenUrl = "https://demo.identityserver.io/connect/token"
                        },
                    }
                });

                configure.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles();

            app.UseHttpsRedirection();
            app.UseRouting();

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

            // Add OpenAPI/Swagger middlewares
            app.UseOpenApi();
            app.UseSwaggerUi3(ConfigureSwaggerUi);

            app.UseEndpoints(endpoints =>
            {
                endpoints
                    .MapControllers()
                    .RequireAuthorization(new AuthorizeAttribute { AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme });
            });
        }

        private static Action<SwaggerUi3Settings> ConfigureSwaggerUi =>
            settings =>
            {
                settings.OAuth2Client = new OAuth2ClientSettings
                {
                    ClientId = "interactive.confidential.short",
                    ClientSecret = "secret",
                    AppName = "Weather",
                    UsePkceWithAuthorizationCodeGrant = true
                };
            };
    }
}

But it has some disadvantages.

  • if an access token expired then you cannot do anything, just logout login again — badly uncomfortable
  • API methods protected but swagger UI page is opened for all world

To solve these drawbacks swagger endpoints should be protected, and a client for OAuth 2 should work correctly.

#swagger-ui #swagger #openid-connect #csharp #identityserver4 #c++

C# protecting Swagger endpoints
8.20 GEEK