Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

A WebAPI Basic Authentication Authorization Filter


ASP.NET Web API allows for a number of different ways to implement security. The 'accepted' way to handle authentication is to use either IIS's built in security (ie. rely on HttpContext and the IIS authentication through Windows Security) or you can roll your own inside of Web API using Web APIs message semantics. If you roll your own the recommended way for authentication is to create a MessageHandler and then add Authorization with a Filter. AFAIK, Web API natively doesn't ship with any authentication handlers at all, so you pretty much have to roll your own if you want to host outside of IIS.

Anyway, in one of my apps for a customer we needed custom user authentication based on user credentials from the business layer and the client explicitly requested Basic authentication due to the client side requirements. Basic Authentication is easy and support by just about any Web client, but it's not secure and requires that SSL is used to keep the encoded (not encrypted) credentials somewhat safe from simple attacks. In this case the app runs on an internal network so the risk factor is low.

Filter Only?

When I looked at the various options at implementing custom login security outside of ASP.NET, the first thing I found was Authorization filters. Authorization filters are a really easy way to examine the request, determine whether a user has access and then either going on or exiting out with an UnauthorizedAccess exception.

Filters aren't meant to be full on HTTP request managers that return results - typically that's meant for MessageHandlers in Web API - but Basic Authentication is such a simple protocol that requires just a few lines of code to implement, so I went ahead and implemented the entire protocol in the filter. Since in this application we have a specific way of authorizing there's only one type of auth happening, there was little need to use a more complex implementation. For contrast in my next post I also implement a message handler based Basic Authentication implementation, so you can easily compare the two if wish.

Authorization Filters in ASP.NET Web API

An Authorization filter inherits from the AuthorizationFilterAttribute class and typically overrides the OnAuthorization() method which should handle the authorization tasks. The filter should do nothing to allow a request through if authorization is valid, throw a UnauthorizedException() if it fails to validate a user, or return a new custom HttpResponseMessage.

Here's the somewhat generic Authorization filter version I ended up with:

/// <summary>
/// Generic Basic Authentication filter that checks for basic authentication
/// headers and challenges for authentication if no authentication is provided
/// Sets the Thread Principle with a GenericAuthenticationPrincipal.
/// 
/// You can override the OnAuthorize method for custom auth logic that
/// might be application specific.    
/// </summary>
/// <remarks>Always remember that Basic Authentication passes username and passwords
/// from client to server in plain text, so make sure SSL is used with basic auth
/// to encode the Authorization header on all requests (not just the login).
/// </remarks>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class BasicAuthenticationFilter : AuthorizationFilterAttribute
{
    bool Active = true;

    public BasicAuthenticationFilter()
    { }

    /// <summary>
    /// Overriden constructor to allow explicit disabling of this
    /// filter's behavior. Pass false to disable (same as no filter
    /// but declarative)
    /// </summary>
    /// <param name="active"></param>
    public BasicAuthenticationFilter(bool active)
    {
        Active = active;
    }
        

    /// <summary>
    /// Override to Web API filter method to handle Basic Auth check
    /// </summary>
    /// <param name="actionContext"></param>
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (Active)
        {
            var identity = ParseAuthorizationHeader(actionContext);
            if (identity == null)
            {
                Challenge(actionContext);
                return;
            }


            if (!OnAuthorizeUser(identity.Name, identity.Password, actionContext))
            {
                Challenge(actionContext);
                return;
            }
            
            var principal = new GenericPrincipal(identity, null);

            Thread.CurrentPrincipal = principal;

            // inside of ASP.NET this is required
            //if (HttpContext.Current != null)
            //    HttpContext.Current.User = principal;

            base.OnAuthorization(actionContext);
        }
    }

    /// <summary>
    /// Base implementation for user authentication - you probably will
    /// want to override this method for application specific logic.
    /// 
    /// The base implementation merely checks for username and password
    /// present and set the Thread principal.
    /// 
    /// Override this method if you want to customize Authentication
    /// and store user data as needed in a Thread Principle or other
    /// Request specific storage.
    /// </summary>
    /// <param name="username"></param>
    /// <param name="password"></param>
    /// <param name="actionContext"></param>
    /// <returns></returns>
    protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            return false;

        return true;
    }

    /// <summary>
    /// Parses the Authorization header and creates user credentials
    /// </summary>
    /// <param name="actionContext"></param>
    protected virtual BasicAuthenticationIdentity ParseAuthorizationHeader(HttpActionContext actionContext)
    {
        string authHeader = null;
        var auth = actionContext.Request.Headers.Authorization;
        if (auth != null && auth.Scheme == "Basic")
            authHeader = auth.Parameter;

        if (string.IsNullOrEmpty(authHeader))
            return null;

        authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));

        var tokens = authHeader.Split(':');
        if (tokens.Length < 2)
            return null;

        return new BasicAuthenticationIdentity(tokens[0],tokens[1]);
    }


    /// <summary>
    /// Send the Authentication Challenge request
    /// </summary>
    /// <param name="message"></param>
    /// <param name="actionContext"></param>
    void Challenge(HttpActionContext actionContext)
    {
        var host = actionContext.Request.RequestUri.DnsSafeHost;
        actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
        actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
    }

}

This code relies on a customized BasicAuthenticationIdentity class that extends the standard GenericIdentity with a password:

public class BasicAuthenticationIdentity : GenericIdentity
{
    public BasicAuthenticationIdentity(string name, string password)
        : base(name,"Basic")
    {
        this.Password = password;
    }

    /// <summary>
    /// Basic Auth Password for custom authentication
    /// </summary>
    public string Password { get; set; }
}

The implementation of the filter is pretty straight forward and handled in a few distinct steps:

  • Parsing credentials into a BasicAuthenticationIdentity if available
  • If no credentials were found Challenge for Authorization (401 Response)
  • If credentials were found authorize the user based on the credentials
  • Set the ThreadPrinicipal (or HttpContext.User) if credentials are valid

Basic Auth is - basic

One of the reasons basic auth is often fallen back to is that it's - basic. It's very simple to implement because the data travelling over the wire is simply a user name and password encoded as a base64 string separated by a :.

username:password

The whole thing is then base64 encoded:

dXNlcm5hbWU6cGFzc3dvcmQ=

An inbound Authorization header from the client, that sends a username and password then looks like this:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Because it's so basic it's also fairly insecure. Remember in real world scenarios to use SSL with Basic Authentication accessed APIs to minimize exposure of the plain text username and password!

Authorization

The ParseAuthorizationHeader() method in the filter then decomposes the Authorization header and reconstitutes username and password into a BasicAuthenticationIdentity which simply holds the username and password so that the Authorization process can determine whether that user and password combination is valid.

The filter contains a very simple OnAuthorize() method that can be overridden in a subclass. This method simply should return true or false and should implement any business logic necessary to determine whether the user is authorized or not. You can validate against a business object, or you could even validate against local or domain Windows accounts given that you have a username and password to work with.

The default implementation simply checks for presence of the Authorization header and returns true.

Here's an example of specialized BasicAuthenticationFilter that uses a business  object to validate the user:

public class MyBasicAuthenticationFilter : BasicAuthenticationFilter
{

    public MyBasicAuthenticationFilter()
    { }

    public MyBasicAuthenticationFilter(bool active) : base(active)            
    { }


    protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        var userBus = new BusUser();

        var user = userBus.AuthenticateAndLoad(username, password);
        if (user == null)
            return false;

        return true;
    }
}

To use the filter now you can simply add the attribute to a controller you want to apply it to:

[MyBasicAuthenticationFilter]
public class QueueController : ApiController

or you can globally apply it in the Web API configuration:

GlobalConfiguration.Configuration.Filters.Add(new MyBasicAuthenticationFilter());

Additionally you can also apply the filter attribute on an individual method to either enable or disable the authentication functionality.

[MarvelPressAuthorizationFilter(false)]
[GET("Queue")]
public IEnumerable<QueueMessageItem> GetRecentMessages(string type = null)

Generally I prefer the first approach, since in most of my apps I have at least one section where the authentication security doesn't apply. For this filter it probably doesn't matter, but if you're using something like token based security you might have a Login API that needs to be accessible without authentication. If you need to keep an individual method (like a Login method!) from firing authentication you can use the last approach and add an attribute with the active=false parameter.

This works pretty well, and it's all fully self contained. What's also nice about this simple implementation is that you have some control over where it is applied. It can be assigned to global filters to fire against every request or against individual controllers and even individual action methods. With a MessageHandler this is considerably more involved as you have to coordinate between a MessageHandler and a Filter to decide where to apply the message handler.

Do we need a Message Handler?

Most other examples I looked at involved message handlers which are a bit more involved to set up and interact with. MessageHandlers in WebAPI are essentially pre-and post request filters that allow to manipulate the request on the way in the response on the way out. To effectively build an authentication message handler is a bit more work than the code I have above. MessageHandlers are also fully async so you have to deal with tasks (or async/await at least) in your code which adds some complexity.

An authentication message handler typically only would have to deal with checking for authentication information in the HTTP headers and if not there fire the challenge requests. Authorization is left to other mechanisms - like a filter. The handler then sets up a principal that can be checked later. The handler also has to check the response output to determine whether to challenge the client. So with a Message Handler implementation you'd have a two fold implementation: the message handler plus an AuthorizationFilter to validate the user.

For reference I also wrote a blog post about a Basic Authentication MessageHandler. It's a little more involved, but most of the code is similar, just a bit more scattered - you can check it out for yourself and take your pick from the two implementations.

I do think that if you are building a generic authentication mechanism that is universally usable, then a MessageHandler makes sense. You can combine multiple message handlers and authentication schemes for example.

But for simple use cases where you use a very application specific custom logon scheme - you are not going to care about other security implementations, so the filter actually makes sense because it keeps all the code for managing the authentication and authorization logically together.

This has been a nice and simple and self-contained solution that's easy to reuse and I've used it on a few projects now. I hope some of you find this useful as well.

Resources

Make Donation
Posted in Web Api  Security  


Feedback for this Post

 
# re: A WebAPI Basic Authentication Authorization Filter
by David Ruttka April 19, 2013 @ 8:29am
Looks like good stuff, thanks for sharing! =) I had a couple of thoughts while reading through it that I felt it was easier to express in code. Here's the pull request https://github.com/RickStrahl/WestwindToolkit/pull/1
# re: A WebAPI Basic Authentication Authorization Filter
by Rick Strahl April 19, 2013 @ 11:25am
@David - thanks. Those are good fixes and I've merged them in. Appreciate it - missed the challenge in refactoring :-)
# re: A WebAPI Basic Authentication Authorization Filter
by Danillo Corvalan April 19, 2013 @ 11:31am
Does the client who access this API have to pass this authentication on every request ? Or do you have to implement an access-token-ish way to deal with that ?

Thanks for sharing!
# re: A WebAPI Basic Authentication Authorization Filter
by Rick Strahl April 19, 2013 @ 11:54am
@Danillo - Basic Authentication requires the Authorization header on every request so every request is authenticated, so either the header needs to be there or the challenge is fired every time (as it does unless you pre-authenticate with windows HTTP clients).

I built token based auth for the app described above initially (and I may publish that next), but the customer actually did not want to go with that for this API - it's actually simpler with most HTTP clients to pass the auth credentials instead of tracking a token and inserting it into the header or URL.

Interesting idea though to use basic auth to request UID/PWD through basic auth in the first place though...
# re: A WebAPI Basic Authentication Authorization Filter
by Fred Besterwitch April 19, 2013 @ 3:21pm
Great article Rick. Very useful for me.

Thanks
# re: A WebAPI Basic Authentication Authorization Filter
by Brad Vincent April 22, 2013 @ 11:02pm
Thanks for sharing Rick - could you also please release your token based auth filter on github - or a blog post about it would be great! thanks
# re: A WebAPI Basic Authentication Authorization Filter
by Dominick Baier April 28, 2013 @ 5:19am
Why would you use an authorization filter for authentication - besides it seems to be the easiest solution....? There are also ordering issues with other (real) authorization filters. Message handlers are a better fit here.

http://leastprivilege.com/2013/04/22/web-api-security-basic-authentication-with-thinktecture-identitymodel-authenticationhandler/
# re: A WebAPI Basic Authentication Authorization Filter
by Dominick Baier April 29, 2013 @ 12:44pm
# re: A WebAPI Basic Authentication Authorization Filter
by Joe May 07, 2013 @ 4:17pm
Thanks for this article. Question... With Basic Authentication the Request is always made with an Authentication header. That part I get. Does that mean on every request to the Web API we are checking whether or not the username/password combination is valid? Would that be overkill to constantly validate the user?

I have an API Controller that returns data for a Get (GetContacts).
The client is a website and is using Jquery for autocomplete (as someone types in a contact it is calling the GetContacts controller with parameters and returning matching contacts for the autocomplete). The problem is that each request is being authetnicated and is slowing down my autocomplete piece. In fact, with the membership.validateuser method I am getting a deadlock (probably because it updates last login or something like that upon validating the user). I'm not sure of a way around this. Have you experienced this before?
# re: A WebAPI Basic Authentication Authorization Filter
by Bruno May 15, 2013 @ 7:31am
Hi Rick:
Excelent post !! very usefull !!
I have the same problem than @Joe. It's a bottle neck in my users controller.
I try to resolve this caching my users table in a application variable with a sql dependency. So my users are always in memory and don't need to invoke the sql server every time.
Do you think that its a good practice ?
# re: A WebAPI Basic Authentication Authorization Filter
by Rick Strahl May 25, 2013 @ 4:29pm
@Joe and @Bruno - I agree I also try to avoid the repeated hitting of the Db to authenticate, but with API's or Services this is a lot more difficult than with typical HTML based Web Application.

That's because the browser tends to provide some state at least - typically in the form of cookies or an auth ticket, that can be persisted as part of the request and then read from the session data (ie. a Forms Authentication Ticket's user data structure). API applications typically can't rely no this mechanism because you can't easily pass cookies to an API. It's possible to do this, but you need to use a token that can encapsulate some of this information you might want to reuse.

Basic Authentication however, is such a simple protocol and all it provides is a username and password, so there's really no way to provide other information.

If you need anything more sophisticated you really need to look into token based authentication and figure out a way to create an encrypted custom token that contains additional data that can vouch for the user's authenticity and potentially provide some additional state without hitting the db. In that case you can optionally use Basic Authentication to actually authenticate initially to get a token returned that can then be reused later. Or simply implement an authentication style method where username and password are passed in.

Just understand that Basic Authentication can't handle that though because it's neither encrypted nor can contain additional data that would be meaningful to identify a valid logon.
# re: A WebAPI Basic Authentication Authorization Filter
by Alex August 16, 2013 @ 6:03am
Hello! Very nice explanatory article having it all together.
You made the same mistake I did in ParseAuthorizationHeader. According to the RFC (http://www.ietf.org/rfc/rfc2617.txt), it is valid for the password to contain a colon ':' character. Except from the RFC

user-pass = userid ":" password
userid = *<TEXT excluding ":">
password = *TEXT

So the solution here is instead of Split to use IndexOf, something like this:

int splitOn = authHeader.IndexOf(':');
string userName = authHeader.Substring(0, splitOn);
string password = authHeader.Substring(splitOn + 1);


Regards
# re: A WebAPI Basic Authentication Authorization Filter
by Zygimantas November 24, 2013 @ 3:50pm
Alex,

There is a bug in your code - you will get an exception if authHeader does not contain colon symbol.

I would recommend to use the original code with the minor modification:

var tokens = authHeader.Split(new char[] { ':' }, 2);
if (tokens.Length < 2)
{
return null;
}
# re: A WebAPI Basic Authentication Authorization Filter
by Rick Strahl November 25, 2013 @ 12:28am
@Zygimantas - not sure what you mean. If there's no : the array will return a single item that is the original string and then exit because the lenght will be 1.

"asdasdasd".Split(':').Dump()


produces a 1 element array which correctly works in the code above which returns null.
# re: A WebAPI Basic Authentication Authorization Filter
by Passenger January 10, 2014 @ 5:40am
@Rick, Zygimantas meant there is bug in Code from Alex.

That aside, Alex is right, your code won't work correctly, when password contains colon char, i just hit that bug today.

Example:
"user:passwith:xyz".Split(':')[1].Dump(); // tokens[1]

tokens[1] is "passwith" and it should be "passwith:xyz"
# re: A WebAPI Basic Authentication Authorization Filter
by Pete S. January 15, 2014 @ 12:31pm
Dear Rick, Thanks alot for this code. I wanted some basic authorization for some prototyping and this made it super easy. Cheers Pete
# re: A WebAPI Basic Authentication Authorization Filter
by Rik Hemsley February 22, 2014 @ 5:00am
Hi,

I've added this to my app but I'm finding that none of the code is called. I've added the attribute to action methods, controller classes, and 'globally' as shown, but nothing seems to cause the code to be used.

I can see that Basic auth is in use - I get unauthorised from BasicAuthenticationModule.

Any idea why it's not hooking up? I have breakpoints on every method!
# re: A WebAPI Basic Authentication Authorization Filter
by Rick Strahl February 22, 2014 @ 3:05pm
@Rik - What's the basic authentication module? If you're using an auth filter, there should be no other basic auth processing happening on the ASP.NET pipeline.

The basic auth module from IIS validates against Windows credentials, but you need to remove that from the pipeline because it'll validate before WebAPI ever gets fired. Enable Basic auth on the site, though, but no module to handle the auth.
# re: A WebAPI Basic Authentication Authorization Filter
by Bassem Mohsen May 28, 2014 @ 10:16pm
Thank you for the great article! It helped me a lot.

But why did you decide to have a Password field in your BasicAuthenticationIdentity class? I think the password will not be needed after authentication and it is a bit unsafe to have the password floating around like that.
# re: A WebAPI Basic Authentication Authorization Filter
by HF June 17, 2014 @ 3:43am
Hi,

By using this method, is there a way to logout? The browser keeps sending the user+password, can we invalidate that info?
# re: A WebAPI Basic Authentication Authorization Filter
by Rick Strahl June 17, 2014 @ 1:34pm
@HF - That's a general problem with Basic Authentication because it's not controlled by the server directly but by the client that keeps on sending the header.

The only way I know of is send a 401 authenticate request and have the client basically put in invalid info (or blank info) to fail the authentication. For a WebAPI client this is relatively transparent to do, but obvious if there's any sort of UI involved that is more problematic as a user would have to actually put invalid credentials in.

There's a discussion of this here:
http://stackoverflow.com/questions/233507/how-to-log-out-user-from-web-site-using-basic-authentication
# re: A WebAPI Basic Authentication Authorization Filter
by Philip Raeburn June 26, 2014 @ 10:35am
Hi Rick, I implemented a Web API with Basic Authentication and SSL using a similar approach to yours and requiring https. I have managed to get this working in my Development environment(c#.net 2013) and when I run it I can see the encoded credentials using Fiddler. I deployed the API to one of our servers and when I access the API using a URL it prompts me as expected for Username and Password and after entry works as expected. However when I try to access the API using the JQuery/JavaScript client(below) I used in development I keep getting a 401 error and when viewing in Fiddler it doesn't seem as if those credentials are being passed to the API. Any ideas why this is happening?

function TestData() {
$.ajax({
type: "GET",
url: "https://service.guinnessworldrecords.com/GWR_Apps_API/Contacts/GetTest",
success: function (result) {
if (result) {
alert(result);
}
else {
alert("Failed");
}
},
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization",
"Basic " + btoa("username" + ":" + "password"));
}

});
}
# re: A WebAPI Basic Authentication Authorization Filter
by EB August 03, 2014 @ 11:51am
This is great, thanks! The only thing I did different is to implement the IAuthorizationFilter so that I didn't need the MyBasicAuthenticationFilter class. My actual authentication occurs in OnAuthorizeUser().

So, this:
public class BasicAuthenticationFilter : AuthorizationFilterAttribute, IAuthorizationFilter


Instead of:
public class BasicAuthenticationFilter : AuthorizationFilterAttribute


And my attribute looks like this:
[BasicAuthenticationFilter]
public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; }


Thanks again for this post! Great stuff, exactly what I was looking for!!!
# re: A WebAPI Basic Authentication Authorization Filter
by budy December 01, 2014 @ 12:59am
Thanks for the Example. Just wanna Ask,

what is the Bbest way to use custom header using "Authorization" if im using JWT

xhr.setRequestHeader("Authorization","JWT " + btoa("username" + ":" + "password"));
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014