Using basic authentication in a Web API application

Some instructions on how to create implement basic authentication in a Web API application.

Just follow what is shown in the steps and screenshots as shown:

Step 1: Create a new ASP.NET Web application in Visual Studio:

basic authentication in a Web API application

basic authentication in a Web API application

Step 2: Create a new authentication filter

I have created a new folder with which to put any new filter classes:

Create a new class called BasicAuthenticationAttribute. This needs to inherit from AuthorizationFilterAttribute.

using System;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web.Http.Filters;

namespace WebApiAuthenticate.Filters
{
   public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
   {
      public override void OnAuthorization(HttpActionContext actionContext)
      {
         var authHeader = actionContext.Request.Headers.Authorization;

         if (authHeader != null)
         {
            var authenticationToken = actionContext.Request.Headers.Authorization.Parameter;
            var decodedAuthenticationToken = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationToken));
            var usernamePasswordArray = decodedAuthenticationToken.Split(':');
            var userName = usernamePasswordArray[0];
            var password = usernamePasswordArray[1];

            // Replace this with your own system of security / means of validating credentials
            var isValid = userName == "andy" && password == "password";

            if (isValid)
            {
               var principal = new GenericPrincipal(new GenericIdentity(userName), null);
               Thread.CurrentPrincipal = principal;

               actionContext.Response =
                  actionContext.Request.CreateResponse(HttpStatusCode.OK,
                     "User " + userName + " successfully authenticated");

               return;
            }            
         }   
         
         HandleUnathorized(actionContext);    
      }

      private static void HandleUnathorized(HttpActionContext actionContext)
      {
         actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
         actionContext.Response.Headers.Add("WWW-Authenticate", "Basic Scheme='Data' location = 'http://localhost:");
      }
   }
}

Step 3: Add the filter in your WebApiConfig file

WebApiConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
using WebApiAuthenticate.Filters;

namespace WebApiAuthenticate
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services        
         
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.Filters.Add(new BasicAuthenticationAttribute());
      }
    }
}

Step 4: Ensure basic authentication filter is applied in Values controller

using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http;
using WebApiAuthenticate.Filters;

namespace WebApiAuthenticate.Controllers
{
    [BasicAuthentication]
    [RequireHttps]
    public class ValuesController : ApiController
    {
         // GET api/values
         public IEnumerable<string> Get()
         {
            return new string[] { "value1", "value2" };
         }

         // GET api/values/5
         public string Get(int id)
         {
            return id.ToString();
         }

         // POST api/values
         public HttpResponseMessage Post()
         {
            var response = Request.CreateResponse<string>(System.Net.HttpStatusCode.Created, "Your first POST request!");
            return response;
         }
         public HttpResponseMessage Post(int id)
         {
         
            var response = Request.CreateResponse<string>(System.Net.HttpStatusCode.Created, id.ToString());
            return response;
         }

         // PUT api/values/5
         public void Put(int id, [FromBody]string value)
         {
         }

         // DELETE api/values/5
         public void Delete(int id)
         {
         }
    }
}

Step 5: Create some example credentials

Example username/password credentials separated by ‘:’ are

andy:password in this example.

Obtain the Base64 encoding of “andy:password” using https://www.base64encode.org/

Giving the text “YW5keTpwYXNzd29yZA==” as shown:

Step 6: Test

Using Postman:

Using Fiddler

In the Compose window I make sure the Basic Authentication is set, along with the Base-64 encrypted username:password pair:

Host: localhost:53977
Authorization: Basic YW5keTpwYXNzd29yZA==
Content-Length: 0

On pressing the Execute button we can read the request response contained in the ‘Raw’ window:

And to allow it to return the values, just remove the response code from BasicAuthenticationAttribute class as shown:

using System;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web.Http.Filters;

namespace WebApiAuthenticate.Filters
{
   public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
   {
      public override void OnAuthorization(HttpActionContext actionContext)
      {
         var authHeader = actionContext.Request.Headers.Authorization;

         if (authHeader != null)
         {
            var authenticationToken = actionContext.Request.Headers.Authorization.Parameter;
            var decodedAuthenticationToken = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationToken));
            var usernamePasswordArray = decodedAuthenticationToken.Split(':');
            var userName = usernamePasswordArray[0];
            var password = usernamePasswordArray[1];

            // Replace this with your own system of security / means of validating credentials
            var isValid = userName == "andy" && password == "password";

            if (isValid)
            {
               var principal = new GenericPrincipal(new GenericIdentity(userName), null);
               Thread.CurrentPrincipal = principal;              

               return;
            }            
         }   
         
         HandleUnathorized(actionContext);    
      }

      private static void HandleUnathorized(HttpActionContext actionContext)
      {
         actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
         actionContext.Response.Headers.Add("WWW-Authenticate", "Basic Scheme='Data' location = 'http://localhost:");
      }
   }
}

So that on re-running the GET command in Fiddler we get the values returned as shown:

Consuming the Web Api web service from a console application

A good way of debugging your web service is to consume it from a console app.

Run the Web Api project in one instance of Visual Studio, and in another run the console application as shown:

using System;
using System.Net.Http;
using System.Net.Http.Headers;

namespace WebApiClient
{
   class Program
   {
      public static void Main(string[] args)
      {
         Console.WriteLine("Enter to continue");
         Console.ReadLine();
         DoIt();
         Console.ReadLine();
      }

      private static async void DoIt()
      {
         using (var stringContent = new StringContent("{ \"firstName\": \"Andy\" }", System.Text.Encoding.UTF8,
            "application/json"))
         using (var client = new HttpClient())
         {
            try
            {               
               client.DefaultRequestHeaders.Authorization =
                   new AuthenticationHeaderValue(
                       "Basic",
                       Convert.ToBase64String(
                           System.Text.Encoding.ASCII.GetBytes(
                               string.Format("{0}:{1}", "andy", "password"))));

               // 1. Consume the POST command
               var response = await client.PostAsync("https://localhost:44363/api/values/33", stringContent);
               var result = await response.Content.ReadAsStringAsync();
               Console.WriteLine("Result from POST command: " + result);
               
               // 2. Consume the GET command
               response = await client.GetAsync("https://localhost:44363/api/values/33");
               if (response.IsSuccessStatusCode)
               {
                  var id = await response.Content.ReadAsStringAsync();
                  Console.WriteLine("Result from GET command: " + result);
               }
            }
            catch (Exception ex)
            {
               Console.ForegroundColor = ConsoleColor.Red;
               Console.WriteLine(ex.Message);
               Console.ResetColor();
            }
         }
      }
   }
}

Giving the following output:

Consume web api service

Consume web api service