Basic Authentication in Asp.Net Web API (Rest API)

In my previous articles, we discussed various methods in Asp.Net Web API without any authentication, which means no security provided for API. Today, we discuss how to provide simple basic authentication for the API through username and password.

There are several ways to implement the basic authentication for the API. Here we apply it through Web API attributes. Let’s add new class BasicAuthenticationAttribute to the App_Start folder and add the below code to it.

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

namespace CompanyRestAPI.App_Start
{
    public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (actionContext.Request.Headers.Authorization == null)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);

                actionContext.Response.Headers.Add("Error", "No credentials provided");              
            }
            else
            {
                string authorizationVal = actionContext.Request.Headers
                    .Authorization.Parameter;

                string usernamePasswordString = Encoding.UTF8.GetString(Convert.FromBase64String(authorizationVal));

                string username = usernamePasswordString.Split(':')[0];

                string password = usernamePasswordString.Split(':')[1];

                if (AuthenticateUser(username, password))
                {
                    var identity = new GenericIdentity(username);
                    IPrincipal principal = new GenericPrincipal(identity, null);
                    Thread.CurrentPrincipal = principal;
                    if (HttpContext.Current != null)
                    {
                        HttpContext.Current.User = principal;
                    }
                }
                else
                {
                    actionContext.Response = actionContext.Request
                        .CreateResponse(HttpStatusCode.Unauthorized);

                    actionContext.Response.Headers.Add("Error", "Incorrect Username/password");
                }
            }
        }

        private bool AuthenticateUser(string username, string password)
        {
            return username == ConfigurationManager.AppSettings.Get("UserName") && password == ConfigurationManager.AppSettings.Get("Password");
        }
    }
}

A custom attribute should implement AuthorizationFilterAttribute class and need to override OnAuthorization() method. API is expecting username and password through request header. Username and Password which API gets through request header will validate against the username and password saved in Web.Config file.

If there are no credentials provided or wrong credentials, our Web API returns HttpStatusCode.Unauthorized with the custom error message on the response header. On successful login validation, the API method process the request. We need to convert UserName:Password into Base64 format and send it to API. Then API reads the username and password combination from the Base64 string.

Then we need to declare this authentication attribute for API methods. There are two ways we can declare attribute in Web API, either method level or in WebApiConfig.Register() method to apply for all methods within the API.

using CompanyRestAPI.App_Start;
using CompanyRestAPI.Models;
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace CompanyRestAPI.Controllers
{
    /// <summary>
    /// Employees Controller
    /// </summary>
    public class EmployeesController : ApiController
    {
        /// <summary>
        /// Get all employees
        /// </summary>
        /// <returns></returns>
        // GET: Employees
        [Route("api/employees/getemployees")]
        [HttpGet]
        [BasicAuthentication]
        public HttpResponseMessage GetEmployees()
        {
            try
            {
                return Request.CreateResponse(HttpStatusCode.OK, Company.GetEmployees());
            }
            catch (Exception ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }
        }

    }
}

As shown above, we have applied the BasicAuthentication attribute at the GetEmployees() method level by declaring it on top of the method.

using CompanyRestAPI.App_Start;
using Newtonsoft.Json.Serialization;
using System.Web.Http;

namespace CompanyRestAPI
{
    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.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

            config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;

            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

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

In the above code, we are applying the BasiAuthentication attribute for all API methods by adding it to config.Filters.

Before testing the application, first, we need to convert our username and password into the Base64 format, as shown below.

class Program
{
        static void Main(string[] args)
        {
            string userNamePassword = Convert.ToBase64String(Encoding.Default.GetBytes("admin:admin"));
        }
}

Here we got the value as YWRtaW46YWRtaW4=. Let’s test this application by using the Fiddler tool. Run the API and request for the getemployees() method, as shown below.

We are sending the request to API without any authorization header, and we get the response as HttpStatusCode.Unauthorized (401), as shown below.

Now include the authorization header in the request, as shown below.

It gives the response code as 200 and returns the data as shown below.

 

Download the API code from GitHub at https://github.com/techinfocorner/CompanyRestAPI