Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

A WebAPI Basic Authentication Authorization Filter


:P
On this page:

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(':',2);
        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;
    } /// 
    /// Basic Auth Password for custom authentication ///  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

Posted in Web Api  Security  

The Voices of Reason


 

David Ruttka
April 19, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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

Rick Strahl
April 19, 2013

# re: A WebAPI Basic Authentication Authorization Filter

@David - thanks. Those are good fixes and I've merged them in. Appreciate it - missed the challenge in refactoring :-)

Danillo Corvalan
April 19, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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!

Rick Strahl
April 19, 2013

# re: A WebAPI Basic Authentication Authorization Filter

@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...

Fred Besterwitch
April 19, 2013

# re: A WebAPI Basic Authentication Authorization Filter

Great article Rick. Very useful for me.

Thanks

Brad Vincent
April 22, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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

Dominick Baier
April 28, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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/

Dominick Baier
April 29, 2013

# re: A WebAPI Basic Authentication Authorization Filter


Joe
May 07, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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?

Bruno
May 15, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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 ?

Rick Strahl
May 25, 2013

# re: A WebAPI Basic Authentication Authorization Filter

@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.

Alex
August 16, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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

Zygimantas
November 24, 2013

# re: A WebAPI Basic Authentication Authorization Filter

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;
}

Rick Strahl
November 25, 2013

# re: A WebAPI Basic Authentication Authorization Filter

@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.

Passenger
January 10, 2014

# re: A WebAPI Basic Authentication Authorization Filter

@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"

Pete S.
January 15, 2014

# re: A WebAPI Basic Authentication Authorization Filter

Dear Rick, Thanks alot for this code. I wanted some basic authorization for some prototyping and this made it super easy. Cheers Pete

Rik Hemsley
February 22, 2014

# re: A WebAPI Basic Authentication Authorization Filter

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!

Rick Strahl
February 22, 2014

# re: A WebAPI Basic Authentication Authorization Filter

@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.

Bassem Mohsen
May 28, 2014

# re: A WebAPI Basic Authentication Authorization Filter

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.

HF
June 17, 2014

# re: A WebAPI Basic Authentication Authorization Filter

Hi,

By using this method, is there a way to logout? The browser keeps sending the user+password, can we invalidate that info?

Rick Strahl
June 17, 2014

# re: A WebAPI Basic Authentication Authorization Filter

@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

Philip Raeburn
June 26, 2014

# re: A WebAPI Basic Authentication Authorization Filter

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"));
}

});
}

EB
August 03, 2014

# re: A WebAPI Basic Authentication Authorization Filter

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!!!

budy
December 01, 2014

# re: A WebAPI Basic Authentication Authorization Filter

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"));

Peter
August 05, 2015

# re: A WebAPI Basic Authentication Authorization Filter

Thanks Rick - Great code, it has save me a lot of time.

I have used it to add authentication to my Umbraco Web API using the backoffice login credentials:

public class UmbracoUserAuthentication : BasicAuthenticationFilter
{
    public UmbracoUserAuthentication() { }
    public UmbracoUserAuthentication(bool active) : base(active) { }
 
    protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        return UmbracoContext.Current.Security.ValidateBackOfficeCredentials(username, password);
    }
}

Thanks again.

jon
January 20, 2016

# re: A WebAPI Basic Authentication Authorization Filter

I tried looking into using Identity for doing validation. It's just too complex. 5+ references, 15+ different files. On node.js I could do it with 2 references and a couple of different files. Ideally libraries simplify the process. No such luck with Identity. Glad you had this tutorial that makes it very simple!

Russell
August 30, 2016

# re: A WebAPI Basic Authentication Authorization Filter

I have tried your examples and there is something missing or our site is not configured due to Ninject that make it so the events don't fire. In the filter example the constructor for the basic fires (twice) and then even though I have the overridden OnAuthorizeUser hard coded to return false just for testing the method on the controller is still fired. The overridden OnAuthorization in the basic filter is overridden but it never fires.
Is there something I am missing?

Marcos Hass Wakamatsu
October 10, 2016

# re: A WebAPI Basic Authentication Authorization Filter

Hi Rick thanks for sharing this code! Before that I was relying on forms auth (cookie) for my web api client (iOS app) with this post I had a much cleaner solution (Your Filter + Basic Auth + Https)

Thanks again!
--marcos

Roland
December 19, 2016

# re: A WebAPI Basic Authentication Authorization Filter

Neat. This should be pushed into the official .NET code as quite a few people are asking about this on stack overflow etc.

Thanks a lot for posting this up, saved me a lot of time and gave me a good example to build on further. I made the following changes to allow basic auth to be used on a Web API 2 using the standard user database.

    public ApplicationUserManager UserManager => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();

    protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return false;
        ApplicationUser user = UserManager?.FindByEmail(username);
        return user != null && UserManager.CheckPassword(user, password);
    }

Camilo
April 19, 2017

# re: A WebAPI Basic Authentication Authorization Filter

It looks very well, but I don´t understand why do you use a filter in a method that doesn´t appear in the custom filter:

[MarvelPressAuthorizationFilter(false)]

For the class is "[MyBasicAuthenticationFilter]". They should be equals, shouldn´t they?


Bart
May 11, 2018

# re: A WebAPI Basic Authentication Authorization Filter

As @Zygimantas pointed out, the

var tokens = authHeader.Split(':'); 

should instead be

var tokens = authHeader.Split(':', 2);

to make sure passwords which contain a : will be handled correctly.


Rick Strahl
May 11, 2018

# re: A WebAPI Basic Authentication Authorization Filter

@Bart - thank you. Fixed. I think the Message Handler article has that fixed but I failed to fix it here.


Zea
March 10, 2020

# re: A WebAPI Basic Authentication Authorization Filter

This article acts as if Authorization and Authentication are the same, and uses them interchangeably in almost every place, even in class names. It's not the same, it can't be treated the same, it shouldn't be called the same.


Spark
May 13, 2020

# re: A WebAPI Basic Authentication Authorization Filter

Hi Rick

we are facing an issue, on HTTPS we are not able to get any token in request header.. Any idea what can be the issue?


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