Clean Architecture — JWT Token Authentication in REST API Using ASP.NET Core Identity

Discussing how to implement an application-specific JWT token service provider using ASP.NET Core Identity in Clean Architecture.

Shawn Shi
Geek Culture
7 min readApr 5, 2021

--

Background

OAuth 2.0 is quite popular and is in-fact adopted almost everywhere now. Even if you haven’t developed any OAuth workflows, I am fairly certain that you have used it. Every time you provide consent to allow a specific application to access data on your behalf from Google, Facebook, or GitHub etc., you are using the OAuth 2.0 for authorization. You likely have used OpenID Connect for authentication as well if you have ever looked closer and noticed any id token. But do all authentication and authorization workflows have to use OAuth 2.0 and OpenID Connect? Not really.

Even though many applications I work on utilize OpenID Connect and OAuth 2.0, quite often, I would also get a request to implement a custom token service provider for a specific application. Possible scenarios are requests to add token services to an existing project, or requests for simple projects that do not want the development overhead of implementing OAuth 2.0.

Goals

The primary goal of the article is to discuss how to implement an application-specific token service provider in the Clean Architecture setup, and use JWT token authentication to guard the API endpoints. Particularly, by the end of the article, we will have covered:

  1. Setup ASP.NET Core Identity, including application user and identity DB context.
  2. Support Identity database to be automatically created and seeded with one user with administrator role. We will cover how to use in-memory database for ease-of-use and how to use a full SQL Server.
  3. Define token service and implement service methods to generate proper JWT tokens.
  4. Implement an REST API endpoint to authenticate a user by username and password, and return a valid JWT token.
  5. Test token authentication using a JWT token in the Swagger UI.

System Design

Here is a brief system diagram for the components and technology we will cover in this article.

System Diagram by Author

Getting Started

If you want to browse the actual code while reading, the project in this article is from a GitHub starter project called Clean Architecture with partitioned repository pattern using Azure Cosmos DB, which uses Clean Architecture to organize the projects.

Here is the folder structure for the Infrastructure project. It is a bit long, but it shall provide a high-level overview and also allows us to refer back to locate specific files.

Part 1 — Setup ASP.NET Core Identity with Application User

ASP.NET Core Identity is a membership system that has built-in functionalities to manage users, passwords, user roles, user claims, tokens, email confirmation, etc.. We want to use ASP.NET Core Identity to build our token service provider, so that we adopt the cryptography best practice and get any security updates. For more details on ASP.NET Core Identity, please refer to Microsoft documentation Introduction to Identity on ASP.NET Core.

First, let’s define our application user, which inherits the ASP.NET Core IdentityUser, by adding a few custom properties like First Name and Last Name as examples.

Second, let’s define our application DbContext, which inherits the default ASP.NET Core IdentityDbContext, so that we tell Identity to use our custom application user.

Part 2 — Support Identity database to be automatically created and seeded with one admin user.

Because we are in the Infrastructure project, we are essentially writing a class library for applications like API and Console Apps to utilize. For this reason, let’s write extension methods for IApplicationBuilder. IApplicationBuild is responsible to build an application at start up, and is commonly seen in Startup.cs in applications. In part 4, we will look at the Startup.cs class in a REST API project to discuss how to configure the automatic database creation and seeding.

We make use of the built-in class UserManager to manage users and RoleManager to manage roles, since ASP.NET Core Identity has kindly provided all the boilerplate code and common methods.

The SeedAsync method specifies the users and roles to be seeded. For demo purpose, we will seed two roles, Administrator and Member, and one admin user. I have defined the string values as constants, e.g., Roles.Administrator = “Administrator”.

Part 3 — Define token service and implement one service method to generate proper JWT tokens.

Our token service contract shall be very simple, as the only thing absolutely required is to evaluate a username and a password, and issue a valid access token. Let’s define our token service interface first. Using an interface allows us to use dependency injection to resolve it.

Please note we don’t limit the token to JWT token in the contract, as that shall be defined in the implementation and also allows us to swap in and out different token types too. IP address is technically not required, we will add it here for future use.

Next, let’s define our JWT token implementation of the token service.

Below are the definitions of token, token request and token response, which are rather straightforward classes.

Token class

Token Request class

Token Response class

Part 4 — REST API endpoint to validate a token request and return a JWT token.

Now we get into our ASP.NET Core API project. Again, we will display the folder structure for reference later.

First, before we look at the actual API endpoint, let’s first make sure the Identity database is created and seeded automatically when the API project starts.

  • On project start up in development environment, we will automatically make sure Identity DB is created and seeded by calling the extension methods created in Part 2.
  • SetupIdentityDatabase() is a custom method that sets up ASP.NET Core Identity DB, including connection string, Identity options, token providers, and token services, etc.. It is defined as an extension method in DatabaseConfig.cs. We will use in-memory database for demo purpose so that you don’t have to connect to a full SQL Server. But you can provide a connection string to a SQL Server and uncomment the line right above the in-memory database configuration.

DatabaseConfig.cs for extension methods to configure databases.

Second, let’s see the API endpoint in TokenController. The controller has only one endpoint for demo purpose, and uses MediatR to decouple business logic from endpoints routing, which is what controllers are only supposed to do.

The actual code to handle the business logic of model validation, and generate a JWT token by calling our Token Service, is in the Authenticate class. As you can see, if the code is left in the controller, the controller itself will be very fat and highly coupled.

Finally, let’s make sure we have our configuration values in the app settings. Note the secret is just a random string generated. You should replace with your own. The issuer is the token service provider.

Part 5 — Test our JWT token endpoint

When we run the API project, Swagger UI will allow us to test the new token endpoint. As you can see from the screenshot below, we can retrieve a JWT token using the seeded user.

If we copy and paste the token to jwt.io, we will be able to peek at the content in the JWT token.

If we try to access an endpoint that requires a valid JWT token, we will get 401 Unauthorized.

However, once we add the JWT token from above to our bearer header, we will be able to get data back!

Conclusion

Congratulations! We have implemented our token service provider and a REST API endpoint to serve JWT tokens. Hopefully this will be a useful tool in your toolbox.

In order to focus on token service, I did not discuss how to protect the API endpoints using JWT token and how to configure Swagger UI to work with bearer headers. If you are interested, please refer to the GitHub start project. I can also write another article covering these topics, just leave me a note in the comment!

Many thanks for reading!

The sample code in this article is from a GitHub starter project, which uses Clean Architecture to organize the projects. This project features Partitioned Repository Pattern using Azure Cosmos DB to build scalable backend service, REST API, Azure Functions, React SPA, etc.. Feel free to use the whole starter project or part of it to kick start your next exciting adventure!

For more resources relevant to the project:

--

--

Shawn Shi
Geek Culture

Senior Software Engineer at Microsoft. Ex-Machine Learning Engineer. When I am not building applications, I am playing with my kids or outside rock climbing!