asp-dot-net-logo

Web Api Key Authentication

knowventBanner

If you are a developer like me you probably have plenty of experience using REST API with an API key and secret. What if you want to provide an API rather then consume it while implementing the same security you are familiar with.

ASP.NET Web Api Key Authentication using DelegatingHandler

ASP.NET Web Api provides http message pipeline configuration support. This is how we can authentication each request’s api key and secret token.

WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    config.Routes.MapHttpRoute(
        name: "Api",
        routeTemplate: "Api/{controller}/{action}/{id}",
        defaults: new { id = RouteParameter.Optional },
        constraints: null,
        handler: HttpClientFactory.CreatePipeline(
                                new HttpControllerDispatcher(config),
                                new DelegatingHandler[] { new Identity.AuthMessageHandler() })

    );
}

This snippet new DelegatingHandler[] { new Identity.AuthMessageHandler() }) is were you will want to implement your custom message handler. This is where you can inspect each request to validate the your API key, secret and any other rules you might require.

AuthMessageHandler – The DelegatingHandler

This is where the magic happens. Based on the API key and secret passed in with each request we can either return HttpStatusCode.OK or a `HttpStatusCode.Unauthorized’ code.

public class AuthMessageHandler : DelegatingHandler
{

    private const string AppIdHeader = "key";
    private const string AppTokenHeader = "secret";
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        IEnumerable<string> appIdValues;
        IEnumerable<string> appTokenValues;
        HttpStatusCode responseCode = HttpStatusCode.OK;
        Guid AppIdGuid;
        var DoesHaveAppId = request.Headers.TryGetValues(AppIdHeader, out appIdValues);
        var DoesHaveAppToken = request.Headers.TryGetValues(AppTokenHeader, out appTokenValues);
        ClaimsIdentity identity = null;
        if (DoesHaveAppId && DoesHaveAppToken)
        {
            if (Guid.TryParse(appIdValues.FirstOrDefault(), out AppIdGuid))
            {
                identity = ValidateAuthentication(AppIdGuid, appTokenValues.FirstOrDefault());

                if (identity != null) //Valid User
                {
                    System.Threading.Thread.CurrentPrincipal = new ClaimsPrincipal(identity);
                }
                else//User failed to authenticate
                    responseCode = HttpStatusCode.Unauthorized;
            }
        }
        else//User didn't supply Key/Token
            responseCode = HttpStatusCode.Forbidden;


        return base.SendAsync(request, cancellationToken)
            .ContinueWith(task =>
            {
                var response = task.Result;
                if (responseCode == HttpStatusCode.OK)
                    return response;
                else
                    return request.CreateResponse(responseCode);
            });
    }

    private ClaimsIdentity ValidateAuthentication(Guid apiKey, string secret)
    {

        //Check your api key and secret here
        if(true)
        {
            var identity = new ClaimsIdentity("API");
            identity.AddClaim(new Claim("API_KEY", apiKey.ToString(), null));
            return identity;
        }
        return null;
    }
} 

Just add your out database of key/secret pairs and start validating your ASP.NET WebAPI requests today.

Let me know if this helped or if you have any questions below

Posted in Uncategorized.