ASP.net Core 2.2 JWT Authentication tutorial

Authentication is one of the most important parts of any web application, particularly Web API projects. For decades, cookies and server-based authentication were the easiest solution. However, handling authentication in modern Mobile and Single Page Applications can be tricky, and demand a better approach.

The best-known solutions to authentication problems for APIs are the OAuth 2.0 and the JSON Web Token (JWT).

A JSON Web Token (JWT) is used to send information that can be verified and trusted by means of a digital signature. It comprises a compact and URL-safe JSON object, which is cryptographically signed to verify its authenticity, and which can also be encrypted if the payload contains sensitive information.

JWT authentication and authorization protocols use tokens as a method of carrying just enough data to either authorize a user to execute an action or request data from a resource.

Tokens can be thought of as packets of information that allow some authorization process to be carried out.

What is JWT Authentication

JWT is a compact token format intended for space constrained environments such as HTTP Authorization headers and URI query parameters.

JWTs encode claims to be transmitted as a JSON object that is base64url encoded and digitally signed and/or encrypted. Signing is accomplished using JSON Web Signature and encryption is accomplished using JSON Web Encryption (JWE).

I recommend checking out the original draft documentation to get a broader understanding.

Structure of JSON Web Token

A JWT is represented as a sequence of base64url encoded values that separated by period characters.

Plain Text

Header

The header contains the metadata for the token and it minimally contains the type of signature and the encryption algorithm.

This JWT example header declares that the encoded object is a JSON Web Token, and that it is signed using the HMAC SHA-256 algorithm.

JS

Once this is base64 encoded, it will look similar to the below and forms the first part of our token string

Shell

Payload

A payload consists of claims which are nothing more than name-value pairs of attributes.

Generally speaking a claim is a statement about an entity, as well as additional metadata about the token itself.

The claim contains the information we want to transmit, and that the server can use to properly handle Web Token authentication.

There are multiple claims we can provide;

  • Registered claim names
  • Public claim names
  • Private claim names.

The most common attributes that claims consist of have standard names which are called Registered Claim Names. These typically include:

  • Issued At (iat) – Time token created
  • Expires (exp) – token expiry time
  • Issuer (iss) – Who issued the token
  • Audience (aud) – Who is the token intended for

Information

Times are represented as seconds since Unix Epoch.

A sample payload may look something like this:

JS

Once it is base64 encoded the payload may look something similar too

Plain Text

Signature

The JWT standard follows the JSON Web Signature (JWS) specification to generate the final signed token. It is generated by combining the encoded JWT Header and the encoded JWT Payload, and signing it using a strong encryption algorithm, such as HMAC SHA-256.

The signature secret key is held by the server so it will be able to verify existing tokens and sign new ones.

C#

Typically a complete JWT will look something similar too

Plain Text

Why use JWT Token Authentication

Token-based authentication is stateless, so there is no need to store user information in the session. This provides the ability to scale an application without worrying where the user has logged in. We can easily use the same token for fetching a secure resource from a domain other than the one we are logged in to.

Advantages of Token-Based Authentication

  • Stateless – The token contains all the information to identify the user, eliminating the need for session state.
  • Reusability – A number of separate servers, running on multiple platforms and domains can reuse the same token for authenticating the user. It is easy to build an application that shares permissions with other applications.
  • JWT Security – No cookies so no need to protect against cross-site request forgery attacks (CSRF).
  • Performance –  no server-side lookup to find and deserialize the session on each request, only need to calculate the HMAC SHA-256 to validate the token and parse its content.

Using JWT Authentication in .net Web Api

Dotnet Core has made it fairly trivial to implement JWT based authentication in dotnet core Web Api, although it is not immediately obvious as to how this can be achieved.

In this guide, I will walk through the process starting from generating a new Web API using the terminal commands then moving on to using Jetbrains Rider -A fast & powerful cross-platform .NET IDE. You can just as easily following using VS Code or Visual Studio.

First, create your Web API using the terminal command. In my case I’ll be creating a Document Management API, that essentially enables the processing and managing Document Metadata to provide it to a web application. The API will have several interaction end-points, i.e Interacting with a Python Based Artifical Intelligence & Machine Learning application, Laravel Web Application and Several AWS Lambdas and S3 Storage.

All these applications will be either post or get information from the API. We could obviously use a Service like OAuth or OKTA to handle all the security for us, but these services can get expensive pretty quickly and in this particular instance, the API is a fairly internally focused to primarily share information across several services and applications. Security is obviously always a key concern, but in this particular instance, we’re mostly dealing with Anonymised data, which is also mainly machine generated and mostly contains Index information.

The API will also potentially be accessed several million times a day, therefore on service plans of most of the security vendors, our little start-up could become bankrupt pretty quick smart, so we will manage the risk and monitor.

Initially create the .net core web API project using the terminal command

Shell

This will create a basic stub of the Web API and we can now open it in the IDE or text editor of choice. Once you have the application open the Startup.cs

The first step is to import the two namespsaces we’ll be making use

C#

Before we continue with the code of our StartUp class. Let’s create an simple POCO class that we will use store the Secret that we will store in our appsettings file. You can name this class whatever you want. In my case I have called TokenManagement

C#

We can now also edit our appsettings.Development.json and add a section which we will use to store our token secret string.

JS

Information

We use the appsettings.Development.json because we might have a different token in our Production, Staging etc. environments.

We can now write the code to get our information from the App Settings and make use of it. We’ll do this in the ConfigureServices method

C#

If you debug the application now and set a breakpoint on the secret to ensuring you are able to retrieve the information. If this all works we should be pretty-good shape to continue.

We can now implement the authentication service and add it to our services collection. Implement the following code in your ConfigureServices method

C#

All we now need to do is update our Configure method. To enable CORS and enable our API to be accessed from Any Origin, On ANy Method and allow any header. Remember, we do this because in this particular instance the API is going to be accessed from several sources.

C#

What is CORS ?

A request for a resource i.e. Access to Web API, outside of the origin is known as a cross-origin request. CORScross-origin resource sharing manages cross-origin requests.

Allowing cross-origin requests is helpful, as many websites today load resources from different resources and services. Cross-origin requests, however, mean that servers must implement ways to handle requests from origins outside of their own. CORS allows servers to specify who (i.e., which origins) can access the assets on the server, among many other things.

Why is CORS Necessary ?

The CORS standard is needed because it allows servers to specify not just who can access its assets, but also how the assets can be accessed.

Cross-origin requests are made using the standard HTTP request methods. Most servers will allow GET requests, meaning they will allow resources from external origins (say, a web page) to read their assets. HTTP requests methods like;

  • GET
  • PUT
  • PATCH
  • DELETE

With CORS, a server can specify who can access and which HTTP request methods are allowed from external resources.

How does CORS Manage requests from External resources ?

An HTTP header is a piece of information associated with a request or a response. Headers are passed back and forth between your client and a server when client to wants to use resources hosted on a different server. Headers are used to describe requests and responses.

 The CORS standard manages cross-origin requests by adding new HTTP headers to the standard list of headers. The following are the new HTTP headers added by the CORS standard:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Origin

How to issue JWT Tokens using .net core

Now that we’ve configured our application to make use of JWT tokens, we’re now ready to proceed setting up our application to issue tokens services that connect to it.

We’ll develop a dedicated controller to handle the Authentication mechanism and issue the token. So lets add a new Controller and name is something original and descriptive like AuthenticationController

We will also create a simple POCO for our TokenRequest

C#

At this stage we’ll implement just enough code to make our Auhtentication Controller to work.

C#

We have just enough code for our Authentication controller to work, but obviously its not very functional. What we will do now, so as not to pollute our API controller with too much logic, we’ll develop an Authentication Service. Let’s create the initial interface we want it to implement.

C#

We can now create the class that implements the interface

C#

All this magic in place we can now wire-up our dependency injection. So in Start.cs add the dependency injection to the ConfigureServices.

C#

We can now inject our service into our controller.

C#

Update the RequestToken method to implement our service

C#

Our authentication service will need to connect to some data repository to verify and authenticate the user. We don’t want to pollute our authentication service with any database connectivity logic, so we will make use of the Service layer pattern and dependency injection once more and inject a user management service which will have Database connectivity etc.

We’ll create a simple interface for this logic.

C#

We will go ahead and implement the interface creating a class. In this instance, I will simply return true for brevity.

C#

The full implementation for the user management service is the subject for another blog post. Essentially we may use AWS AMI, Azure Identity or even role our own user authentication system. For the purpose of this post, we’re just returning true, so we can move onto the next phase.

Avoid

Don’t do this in PRODUCTION as essentially every authentication request will be validated to tru

Modify the StartUp.cs again to enable the Dependency Injection.

C#

All the configuration and wiring up is now complete, we can now code our TokenAuthenticationService.

C#

Quite a bit of code there but not all that difficult to understand – hopefully I have managed to pull all the complexity downwards – and easy to read.

Essentially what we do in the code, is call-out to the Authentication Service, verify the user, if there is a success we create a token to pass back. The most important point in the code is line 17 where we start configuring the Claim, which is trusted and repeatedly validated because in most cases it is digitally signed using a private key with the HMAC algorithm.

This signature ensures only a server possessing the key can decode and verify the contents of incoming tokens and grant or deny access to its resources.

The basics of our JWT authorisation is now complete. We can now run the application and start Postman and quickly send in a request and check we get a Token back.

Summary

Token-based authentication enables us to construct decoupled systems that are not tied to a particular authentication scheme. The token might be generated anywhere and consumed on any system that uses the same secret key for signing the token.

JWT is mobile ready, and do not require the use of cookies.

There is still a lot to cover about JWTs, such with how to handle the security details, and refreshing tokens when they expire, but the JSON Web Token tutorial should demonstrate the basic usage and, more importantly, the advantages of using JWTs.

Gary Woodfine

Technical Director at Denizon
Gary is Technical Director at Denizon, an independent software vendor specialising in IoT, Field Service and associated managed services,enabling customers to be efficient, productive, secure and scalable in a way which helps them address and reduce their ecological impact.

Denizon's product line successfully integrate IoT, Artificial Intelligence and Blockchain technology to enable efficient, productive, secure and scalable solutions to help organisations address increasing energy demands, ecological impact and Health & Safety concerns of their staff.

Latest posts by Gary Woodfine (see all)