Light Mode Image
Secure Swagger UI with Basic Authentication in Asp.Net Core
D

Dipendra Neupane

Secure Swagger UI with Basic Authentication in Asp.Net Core

    In this article, we will see how to add Basic Authentication to swagger documentation in an ASP.Net Core Web API application.

     

    Swagger is an open-source tool that has helped many API developers, teams, and organizations to deliver APIs with documentation. There are many Swagger tools, and out of them, Swagger UI is one of the most useful ones. It renders OpenAPI definitions as interactive documentation.

     

    Adding Swagger UI in Asp.Net Core Project is really easy. There are a few Nuget packages that can be installed using the Nuget package manager. After that, a few setups on Program.cs file and you are ready to go. Over time, there might come a situation where you want to secure Swagger UI with at least a Basic Authentication.

     

    It comes really useful when you don’t want to expose your API definition to an unauthorized user due to security reasons.

     

    In this article, I am going to add a layer that will secure swagger UI with Basic Authentication in the Asp.Net Core project.

     

    Create a middleware for Swagger Basic Authentication.

     

    public class SwaggerBasicAuthMiddleware
     {
      private readonly RequestDelegate next;
      private readonly IConfiguration config;
    
      public SwaggerBasicAuthMiddleware(RequestDelegate next, IConfiguration config)
      {
       this.next = next;
       this.config = config;
      }
    
      public async Task InvokeeAsync(HttpContext context)
      {
       if (context.Request.Path.StartsWithSegments("/swagger"))
       {
        string authHeader = context.Request.Headers["Authorization"];
        if (authHeader != null && authHeader.StartsWith("Basic "))
        {
         var encodedUsernamePassword = authHeader.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries)[1]?.Trim();
    
         var decodedUsernamePassword = Encoding.UTF8.GetString(Convert.FromBase64String(encodedUsernamePassword));
    
         var username = decodedUsernamePassword.Split(':', 2)[0];
         var password = decodedUsernamePassword.Split(':', 2)[1];
    
         if (IsAuthorized(username, password))
         {
          await next.Invoke(context);
          return;
         }
        }
    
        context.Response.Headers["WWW-Authenticate"] = "Basic";
    
        context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
       }
       else
       {
        await next.Invoke(context);
       }
      }
    
      public bool IsAuthorized(string username, string password)
      {
       var _userName = config[SettingConstant.SwaggerSetting_UserName];
       var _password = config[SettingConstant.SwaggerSetting_Password];
    
       return username.Equals(_userName, StringComparison.InvariantCultureIgnoreCase) && password.Equals(_password);
      }

     

    Middleware in Asp.Net Core is a piece of code in an application used to handle requests and responses. Middleware can be built-in or custom, you definitely are already using it knowingly or unknowingly while working on Asp.Net Core projects.

     

    SwaggerBasicAuthMiddleware is the custom middleware that will help to authenticate the user with the username and password before displaying the Swagger page.

     

    All our authentication logic resides inside SwaggerBasicAuthMiddleware so, let’s understand each line of code from there.

     

    if (context.Request.Path.StartsWithSegments("/swagger"))
    {
    
    }

     

    This part of the code will check if the URL starts with the text “/swagger”. You can change it based on your requirement. We will be setting the starting URL of Swagger as “/swagger” on program.cs.

     

    string authHeader = context.Request.Headers["Authorization"];
    if (authHeader != null && authHeader.StartsWith("Basic "))
    {
     
    }
    
    context.Response.Headers["WWW-Authenticate"] = "Basic";
    context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;

     

    When the middleware is invoked for the first time, authHeader variable will return null, and if block will not be executed. The code above will display the pop-up for username and password on the first call. Once username and password are provided, below code block will get executed.

     

    if (authHeader != null && authHeader.StartsWith("Basic "))
    {
       var encodedUsernamePassword = authHeader.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries)[1]?.Trim();
      
       var decodedUsernamePassword = Encoding.UTF8.GetString(Convert.FromBase64String(encodedUsernamePassword));
      
       var username = decodedUsernamePassword.Split(':', 2)[0];
       var password = decodedUsernamePassword.Split(':', 2)[1];
      
       if (IsAuthorized(username, password))
       {
          await next.Invoke(context);
          return;
       }
    }

     

    Here we are decoding the username and password from authHeader and comparing them with the username and password from appsettings.json.

     

    public bool IsAuthorized(string username, string password)
    {
       var _userName = config[SettingConstant.SwaggerSetting_UserName];
       var _password = config[SettingConstant.SwaggerSetting_Password];
      
       return username.Equals(_userName, StringComparison.InvariantCultureIgnoreCase) && password.Equals(_password);
    }

     

    Now register the SwaggerBasicAuthMiddleware in the program.cs like below.

     

    builder.UseMiddleware<SwaggerBasicAuthMiddleware>();
    
    builder.UseSwagger();
    builder.UseSwaggerUI(c =>
    {
       c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });

     

    Please make sure you have registered SwaggerBasicAuthMiddleware before builder.UseSwaggerUI({}) because the swagger UI URL is dependent on our middleware.

    04 Dec 2023
    By Dipendra Neupane
    ;