Previously we provided an Overview of our .Net Core API to describe the setup and API behavior.
Next we will look at some key C# coding points, which enabled us to produce equivalent behavior to our earlier Node JS API Code.
Web API Code Overview
Our API code aims to demonstrate how to get the tricky OAuth plumbing out of the way so that you can focus on growing your company’s API logic.
Our API’s ‘business logic‘ is a trivial controller that returns hard coded data from JSON text files. We are treating this as ‘sensitive corporate data‘ that must be protected via OAuth access tokens.
Loading Custom Configuration
Our Web API uses custom JSON configuration, and this would be delivered by your Continuous Delivery process. If required you can combine standard Microsoft sections with your own custom ones.
Our sample provides a couple of extension methods for the IConfiguration interface, to load our custom data points into objects:
Creating the Web Host Listener
We create the web host to listen over SSL, based on the details in the configuration file.
If we ignore OAuth handling, the rest of our API startup is boiler plate ASP.Net Core configuration that you can read about in many online articles.
Note that our sample API also serves up our sample SPA’s static content, and of course a real API would not do this:
JWT Bearer API Authentication
Microsoft Authentication Middleware works by calling AddAuthentication and then selecting a Authentication Method to say how it will work.
Meanwhile an Authorization Filter indicates which controller operations need to be secured by the authentication method:
As can be seen the most commonly used out of the box option for OAuth Secured APIs is JWT Bearer In Memory Token Validation.
This may work fine for your company but this blog prefers an alternative solution due to the Design Aspects we covered earlier.
Configuring Identity Model Authentication
For our API we will therefore use an alternative authentication method of Identity Model Token Introspection. This method will also be commonly used by companies who use Reference Tokens rather than JWTs.
The full Identity Model configuration is shown below, and uses the OAuth settings from our custom configuration. We also indicate that we will cache introspection results until the token expiry time.
A few points of particular interest:
- We use the Microsoft Memory cache for Claims Caching
- To introspect JWTs we need to unset SkipTokensWithDots
- We added a helper class to enable HTTPS Proxy Debugging
Microsoft logging works in terms of a ‘logger per class’, and as an example the Identity Model introspection handler creates its logger as follows:
Our Sample API creates its own loggers and also applies a Logging Filter to limit output to just the areas we are interested in:
API Controllers and Authorization
Once Identity Model processing has completed, validated requests are assigned a Claims Principal for use within your API controllers:
Your business logic can then easily access claims in its API logic, to authorize requests for Corporate Assets.
It Just Works …
And that is pretty much all we need to do to implement our Preferred API Architecture. The running API with logging is shown below:
I like the design of the new Microsoft Web API stack, and the Identity Model library integrates with it very easily.
API Unhandled Exceptions
To finish up we will ensure that we are handling errors in a solid manner. First we added a simple Unhandled Exception Handler to catch any errors in our business logic:
We can simulate an error by changing our repository class to use an invalid JSON file location. First we see that the exception is caught and logged:
Next we see that a controlled error is returned to the UI for display:
API Authentication Errors – Default Behavior
One thing I did not like about the Microsoft stack is that any error during authentication processing is returned as an empty 401 response, and there is no opportunity to log the error or customize the response.
The empty 401 is not too bad if the reason for the failure is a missing or invalid access token, but the error could be a permanent failure:
- API is misconfigured and Okta introspection always fails
- API is unable to connect to Okta and authentication always fails
In these cases, the response we are returning to our caller is not consumer friendly and may lead to problems such as redirect loops.
API Authentication Errors – Custom Behavior
To implement my preferred behavior I had to resort to a minor code hack, since it seems there is currently no easy way to extend Microsoft’s authentication error handling.
In the above statement I replaced the Microsoft AuthenticationMiddleware class with my own CustomAuthenticationMiddleware class. The custom implementation just calls registered handlers then handles errors.
I can now return more consumer friendly errors, which I would expect to enable my company to resolving any production issues more quickly.
Of course, the above code ensures that for any type of authentication error we avoid moving onto subsequent middleware, deny access and avoid returning any sensitive information to the caller.
To see the new behavior, we can configure the API to use a proxy when calling Okta, but also ensure that Fiddler or Charles are NOT running:
Our API will now experience a connection error that is logged, which we hope will help us to understand incidents and quickly resolve them:
Our API consumers now get responses they can work with, as for our SPA, whose display references the details we logged server side:
Where Are We?
The .Net Core Web API stack is easy to use and we made a good library choice in Identity Model, so it has been easy to deliver our API Architecture.
We had to spend a little time to get our technical foundations and reliability in good shape. We can now focus on growing our API’s business logic.