Using .net core middleware to validate client credentials when building a third party API.

simi
5 min readOct 19, 2020

In this tutorial, we would be learning about .net core middleware, and using it specifically in a real world scenario.

Real world problem

As a backend developer that works with API, if you have not before, there would be a time you would build an API that would be needed to be consume by third party apps. In this scenario, you would have to issue every consumer of your API, an API Key /or Client ID or both. Now, on every request, you have to check if the Client Credentials (API Key/Client ID) is the one you issued. That’s where the middleware comes in.

Thus in this tutorial, we would be writing a middleware that checks every request for correct client Credentials before we even get to the controller. I find this particular method to be efficient compared to writing or interfacing a method to check for correct client credentials on every API method.

A single point of failure. A single check.

Before we begin

What’s a middleware?

A service that runs in between requests and responses. So think, request traveling from point client to server. Middleware are those services that are set up to inspect, monitor, detect, check and a lot bunch of other things on the request.

Specifically to the .net core design, you would hear the request pipeline which is where you fix the middleware in your apps. Each middleware does its job and pass it to the next and to the next until your response is served.

Let’s begin

Step-1: Create a new web API

Use your favorite IDE (hopefully Visual Studio Code/ Visual Studio) and create a new web API using the provided template.

dotnet new webapi

Step-2: Add a new controller

From the base template given by the .net team. You should have two controllers inside the controllers folder. Add a new one. Call it any name you want. (called mine AuthorizedController).

This new controller, is an authorized route. The WeatherForecastController is the public route.

Authorized route being, you have to supply client credentials before you are granted access. Public route means no need to supply client credentials.

Note: Client Credentials can be either client Key or Client ID. Your choosing

In the AuthorizedController class create some methods. It doesn’t mean what the method does, just that the controller works. For example, here are some methods in mine:

If you run it now, all the controllers should be displaying the right output based on the HTTP Method.

Step-3: Decorating the API Controllers.

We briefly mentioned the public and authorized route, so how do we distinguish it?

By decorating the API the controllers, which for the cause of this tutorial I chose a rather crude approach. Appending the route with different prefixes.

So the AuthorizedController is decorated like this.

[ApiController]
[Route("api_s/[controller]")]

And WeatherForecastController looks like this:

[ApiController]
[Route("api_p/[controller]")]

see the difference yet?….api_s and api_p

You can choose your route differentiation differently but as a rule of thumb, make sure public and authorized route are differentiated at the controller level.

Step-4: Implementing the middleware

Create a folder called Middlewares, then add a class (named mine HeadersCheckers.cs). Add this code then I explain.

A typical middleware in .net core must contain 3 things:

  • a RequestDelegate Object (line 3),
  • a constructor that accepts a RequestDelegate (line 7),
  • the Invoke method (line 12) which is fired when the requests enters this middleware.

The RequestDelegate object _next is responsible for forwarding the processed request to the next middleware in the pipeline.

Line 4 and 5 we declared a static string to compare against the client credentials that is sent.

To the Logic which begins on Line 12

The Invoke method has access to the HttpContext object which contains the request. (As a research find out other Objects/Service the Invoke method has access to).

So we:

  • check the request path (Line 14,15, 18). If the request path is the secured Path (api_s), we perform the check. If not, we pass the request through.
  • In the If-block that starts from line 18–29 we get the headers that have the keys: ClientId and ClientKey. Then we check if it compares to the one we defined in the class. If it does we pass the request, if not we redirect it to an error controller.
  • Line 32 we pass the request to the next middleware.

Note: It is assumed that in this scenario, we issued the third party app a clientId and clientKey. It might be different for your case.

pitch-stop, here is how my custom error controller (ErrorController.cs) form line 28 looks like.

[Route("api/error/")]
[ApiController]
public class ErrorController : ControllerBase
{
[HttpGet("401")]
public ActionResult Return401Error()
{
var errorResponse = new ErrorResponse { Code = "E01", Msg =
"Invalid client credentials, kindly check and try again" };

return Unauthorized(errorResponse);
}
}
  • Then the last part, Line 37-42, is where we registered the middleware using ApplicationBuilder object. The method on line 39 (UseHeaderCheckerMiddleware) is the one to be called in the startup to effect this middleware.

Step-5: Using the middleware

This is the last part of the puzzle, add a one liner to your startup.cs file, just before the app.UseEndpoints(). Which should read:

app.UseHeaderCheckerMiddleware()

And like that we have implement header check on all the authorized routes. Clean and simple init??

A note to remember: The order in which the middleware are added is the order in which they are ran. Thus why I chose to call the headers middleware just before we call the UseEndpoints() middleware.

Voila. We have successfully added a client credential verification to our app.

Closing Notes

The obvious question would be you, “hey man used static client credentials, but the client credentials is stored in the database how do we access the database inside our middleware?” Well accepting ApplicationDbContext object in the Invoke method would do the trick. Another idea would be to implement a service that does the header checking, then inject the service into the middleware.

And That’s it.

Thank you for your time.

Use middleware in your next project.

Here is the link to the code on github.

--

--

simi

I write about software and at other times about not-software