Protect Web API using Your Own Authentication Server

Discuss how to protect a web API application with JWT token authentication using your own authentication server leveraging Identity Server.

Shawn Shi
Geek Culture
5 min readFeb 20, 2023

--

Diagram by author. Icons from flaticon.com.

How can a web API get protected by an authentication server?

Let’s imagine the web API and the authentication can talk…

  1. Web API says: “Mighty authority, protect my precious land please…”
  2. Authentication server says “Sure, I will do two things to protect you! First I will grant you a name called Farmland. Second, I will issue tickets ONLY to people who I permit to come to your land! From now on, anyone who wants to get something from you, tell them you are protected by me!”
  3. API says “Sweet, thanks. I will build a wall and only allow people who have a ticket from you to come in!”

Background

In a previous article, we discussed how to build your own authentication server for single sign-on using Identity Server and ASP.NET Core. The authentication server is essentially a web application that

  • has UI pages for users to login and logout, i.e., authentication process to prove who they are.
  • can issue JWT token to an authenticated user.

Under the hood, the authentication server has several major components:

  1. User management, such as user name, email, etc.
  2. Configuration data management, such as clients, referring to applications that should have access to the authentication server, identity resources, referring to user identity data; API scopes, referring to web APIs that are protected by the SSO server, etc..
  3. Operational data management, such as refresh tokens generated by the server, and keys for digital signature, etc.

If we have a web API application who needs protection, we can add it to the configuration data store as an API scope, so it will be protected by our authentication server!

Goal

The goal is to discuss how to protect a web API using JWT token authentication scheme, so that it requires a valid JWT token issued by our authentication server.

Getting Started

Let’s start with a barebone web API application called “FarmlandWebApi”, which can be created using the ASP.NET Core Web API template. We will take the following 2 steps to make sure it is protected by our authentication server:

  1. Register the web API with the authentication server
  2. Configure the web API to require a valid JWT token issued by the authentication server

Step 1 — Register the web API with the authentication server

In the conversation above, the authentication server says it will do two things: “First I will grant you a name called Farmland. Second, I will issue tickets ONLY to people who I permit to come to your land!”. Let’s see how that can be done in the code.

First, the authentication server needs to add the web API as an API scope and grant it a name called “farmlandwebapi”.

private static readonly string FarmlandWebApi= "farmlandwebapi";

public static IEnumerable<ApiScope> ApiScopesToSeed =>
new ApiScope[]
{
// Add the farmland web api
new ApiScope(FarmlandWebApi, displayName: "Farmland Web API"),
};

Second, the authentication server also needs to configure which clients can request for tickets for going to the farmland. We have two dummy clients in the following code to demonstrate different types of client.

public static IEnumerable<Client> ClientsToSeed =>
new Client[]
{
new Client
{
ClientId = "m2m.client1",
ClientName = "Sample Machine-to-Machine Client",

AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

AllowedScopes = {
// Add the farmland web api
FarmlandWebApi
}
},

new Client
{
ClientId = "interactive.client1",
ClientName = "Sample Interactive Client",
ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) },

AllowedGrantTypes = GrantTypes.Code,

RedirectUris = { "https://localhost:5002/signin-oidc" },
FrontChannelLogoutUri = "https://localhost:5002/signout-oidc",
PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },

AllowOfflineAccess = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
// Add the farmland web api
FarmlandWebApi
},
}
};

And we need to make sure the above changes are seeded into the database, if seeding is desired. See the last article regarding to data seeding works for such configuration data.

Step 2 — Configure the web API to require a valid JWT token issued by the authentication server

In the conversation above, API says “Sweet, thanks. I will build a wall and only allow people who have a ticket from you to come in!”. Let’s see how that wall can be built in the web API.

  1. Install the necessary packages: Microsoft.AspNetCore.Authentication.JwtBearer: This package provides JWT (JSON Web Token) authentication support. You can install these packages using the NuGet Package Manager or by adding them to your project file.
  2. Configure the authentication scheme as JWT bearer token in the web API application’s Program.cs, , see lines 8–19 below.
  3. Configure the authorization policy to not only require a valid JWT token, but also require a claim called “scope” with a value “farmlandwebapi”. See lines 21–33 below.
  4. Update the HTTP pipeline to use both authentication and authorization. Quick reminder: authentication checks who a user is, authorization checks what a user can do. See lines 51 to 53.
  5. Apply our authorization policy globally so it is enforced on all API endpoints. See line 58.

Done! Now our API is fully protected by a centralized authentication server!

If we have more web API applications, we can do the same thing to add them under protection. The beauty of using an authentication server to do this is that our web API applications no longer need to implement any code to issue JWT tokens, and manage all the signing signatures involved.

The sample code in this article is hosted in a GitHub project. Feel free to check it out! Many thanks for reading!

Related resources:

This is part of a series of articles discussing how to build a centralized authentication server using ASP.NET Core. Other articles can be found here:

  1. Single Sign-On (SSO) Simplified: Understanding How SSO Works in Plain English
  2. Build Your Own Authentication Server for Single Sign-On (SSO) in ASP.NET Core
  3. REST API for User Management in Authentication Server for Single Sign-On
  4. REST API for User Management in Authentication Server for Single Sign-On (2)
  5. Protect Web API using Your Own Authentication Server
  6. Access Web API Protected by Your Own Authentication Server

--

--

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!