Authentication via headers

Simple Web API authentication using request headers

  • Share

Authentication in web services is a bit more different than with web pages because of one simple reason. There is no UI for entering credentials to authenticate to consume service. Credentials need to be supplied during the service call.

There are different ways to do that, open authentication is one of the most common ways to authenticate and use the service and it is widely spreaded among all major REST service providers such as Facebook, Google, Twitter...

There are much more simpler ways to authenticate to use web service than is OpenAuthentication. One of these is authentication throught request headers. Basically credentials are sent in HTTP request and request is authenticated using there credentials supplied through headers.

In the following example I will try to describe simple implementation of this type of service call authentication.

On of the main security risks in this type of authentication is that credentials are sent in plain text, so it is open to anyone who intersects the traffic. That is why HTTPS and SSL needs to be used. Since this sample will explain this type of authentication with WebAPI, we will authenticate using custom attributes.

 public class AuthorizeHeadersAttribute : AuthorizationFilterAttribute
    {
        private bool isAuthorized = false;
        private string usernameKey = "username";
        private string passwordKey = "password";
        private string username = null;
        private string role = null;

        public string UsernameKey
        {
            get
            {
                return this.usernameKey;
            }
        }

        public string PasswordKey
        {
            get
            {
                return this.passwordKey;
            }
        }

        public string Username
        {
            get
            {
                return this.username;
            }
        }

        public string Role
        {
            get
            {
                return this.role;
            }
        }

        public AuthorizeHeadersAttribute()
        {

        }

        public AuthorizeHeadersAttribute(string username, string role, string usernameKey = null, string passwordKey = null)
        {
            this.usernameKey = string.IsNullOrWhiteSpace(usernameKey) ? this.usernameKey : usernameKey;
            this.passwordKey = string.IsNullOrWhiteSpace(passwordKey) ? this.passwordKey : passwordKey; ;
            this.username = username;
            this.role = role;
        }

        public override void OnAuthorization(HttpActionContext actionContext)
        {
            var request = actionContext.Request;
            if (actionContext.Request.RequestUri.Scheme == Uri.UriSchemeHttps && request.Headers.Contains(UsernameKey) && request.Headers.Contains(PasswordKey))
            {
                var usernameHeader = request.Headers.Where(val => val.Key == UsernameKey).FirstOrDefault();
                if (!string.IsNullOrWhiteSpace(this.Username) && this.username != usernameHeader.Value.FirstOrDefault())
                {
                    isAuthorized = false;
                }
                else
                {
                    //TODO: Authorization logic here
                    this.isAuthorized = true;
                    //Authorization logic end
                }
            }


            if (!this.isAuthorized)
            {
                actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
            }
        }

        protected virtual bool IsAuthorized(HttpActionContext actionContext)
        {
            return this.isAuthorized;
        }
    }
    

As you can see there are two main things which we check before we actually check credentials against our members database:

  • Is request through HTTPS protocol
  • Are credentials supplied

This will save us from unnecessary trips to our membership storage (SQL Database, Active Directory, LDAP...)

Note

For the sake of simplicity of this sample, I did not include any authentication logic, simply I allow user to get the response if HTTPS and credentials are supplied

Custom attributes make authentication really easy as you can re-use them anywhere in your code, either on the controller or to specific action in a controller. The following sample applies authentication on the controller level meaning every action in the controller will be authenticated previous with our custom AuthorizeHeadersAttributes class.

namespace WebApiAuth.Controllers
{
    [RoutePrefix("api/test")]
    public class DefaultController : ApiController
    {
        [Route("authtest")]
        [HttpGet]
        [AuthorizeHeaders]
        public HttpResponseMessage Test()
        {
            return Request.CreateResponse(HttpStatusCode.OK, "Hello"); ;
        }
    }
}

    

Now since we refuse to authenticate user if HTTPS protocol is not used, we need to make some small change on the project to use HTTPS during debug.

Ssl Dev Iis

The second thing we need to do to successfully authenticate is to provide authentication header values. Luckily for us there are bunch of Add-ons for all major browsers which can enrich the request with header values. I happen to use Firefox Add-on named Modify Headers. It is not maybe the best one but it does the work.

Simply add header values as following and navigate to your service URL.

Headers Auth

In case of successful authentication, you will see "Hello" message. If the authentication fails, you will get an empty response with a status code 403 (Forbidden).

This maybe not the most elegant way to authenticate a WebAPI call comparing to OpenAuth, but for sure it is one of the simplest and easy to implement.

References

  • Share

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.

Comments for this article

comments powered by Disqus