We have set up our identity server but we lack UI for the users to enter their credentials. We’ve shown how we can retrieve our token but for better user experience, we have to add UI to our Authorization Server. So, adding IdentityServer4 UI is our goal for this article. Additionally, we are going to learn how we can protect our API and the way to access protected resources. This will be a basic protection setup, but we are going to enhance it during this series.

To download the source code for the starting projects, you can visit the IdentityServer4 UI repository (Start folder).

For the ending project’s source code, you can visit the IdentityServer4 UI repository (End folder).

To navigate through the entire series, visit the IdentityServer4 series page.

This article is divided into the following sections:

Installing IdentityServer4 UI and Overview

If we start our authorization server now, we are going to see a not found page in a browser for sure. Even though the server works, this is not user-friendly at all. So let’s do something about that. There is already created UI for the IdentityServer which is easy to install and modify, and we are going to use it for our project.

Before we do that, let’s install the System.Security.Principal.Windows library, because it is required for ExternalController in our UI project we are about to download:

PM > Install-Package System.Security.Principal.Windows -Version 4.7.0

Now, we can continue.

So, the first thing we are going to do is to open a PowerShell window and navigate to the folder where we have our OAuth project (…\CompanyEmployees.OAuth\CompanyEmployees.OAuth). Once the window is up, let’s execute a command to download the entire UI project:

After a couple of seconds, we can see a confirmation about installed Quickstart, Views, and wwwroot folders:

IdentityServer4 UI installed confirmation

File Inspection And Configuration

If we inspect the SolutionExplorer window of our project, we are going to see three additional folders:

IdentityServer4 UI Inspection

We can see the wwwroot folder with the static files required for the UI. There is the Quickstart folder with different controllers, models, and additional classes. Finally, there is the Views folder with different views (.cshtml files) inside. Everything we downloaded is easy to maintain and modify so, this speeds up the UI creation process a lot. For our examples the default created files will be quite enough.

Now, we have to configure this UI.

So, the first thing we are going to do is to modify the Configure method in the Startup class:

With the UseStaticFiles method, we enable serving static files from the wwwroot folder. Additionally, we are adding routing and authorization to the pipeline and configuring endpoints to use a default /Home/Index endpoint. If we open the Quickstart/Home folder, we are going to find a HomeController with the Index action inside. So, this is our entry point.

We have to modify the ConfigureServices method as well:

Excellent. Now, we can test our UI.

Testing IdentityServer4 UI

Let’s start the application. It should automatically navigate to localhost:5005 and show the Welcome page:

Welcome page IS4 - IdentityServer4 UI

If we click the discovery document link, we are going to see different endpoints we’ve been talking about in a previous article.

Let’s click on the here link and enter credentials from one of our test users:

Login IS4 - IdentityServer4 UI

So, we see everything is working as expected. We can logout as well by clicking the username (Mick) and then the Logout link. In the rest of the series, we are going to use this UI quite frequently.

Now, let’s see how we can protect our API using the authorization server.

Configuring API Resources

The first thing we have to do is to add our API resource in the Authorization Server. As we did with the IdentityResources, in a previous article to support different identity-related data, we are going to support our API resource as well. So, let’s add additional code in the InMemoryConfig class in the OAuth project:

As you can see, we can add multiple API resources, but for now, we add only one with the name and displayname parameters.

Additionally, we have to modify the client:

We just add additional scope to support our API resource.

Finally, we have to include this configuration in the ConfigureServices method:

That is all regarding the IdentityServer configuration and we can continue with the API security logic.

Securing Web API

Before we configure our middleware to support IdentityServer, we have to install a Nuget package to help us in the process:

JwtBearer package

After the installation, we can modify the ConfigureServices method in the Startup class:

We use the AddAuthentication method to add authentication services to the IOC in our project. Moreover, we use the AddJwtBearer method to configure support for our Authorization Server. In that method, we specify several options:

  • RequireHttpsMetadata – We set this to false because we are in a development environment and we don’t require HTTPS
  • Authority – Address to use when sending OpenID Connect calls
  • Audience – Audience value for received OpenID Connect tokens. This value has to be the same as the one provided in the authorization server configuration

We have to do one more thing in the Configure class:

Now, all we have to do is to protect our action in the CompaneesController by placing the [Authorize] attribute on top of the action or controller itself. For that, we have to include Microsoft.AspNetCore.Authorization endpoint in the controller.

Let’s start both applications and send a request with Postman:

Unauthorized access to web api

As expected, we get the 401 – Unauthorized response.

Now, to provide access to the authorized resource, we are going to send another request, but to the authorization server first:

Token received from auth server

Great, we have a token. Let’s copy our token and add it to the previous request as the Authorization parameter in the Headers tab:

Retreived data from API

And, there we go. We have the required data. So, we are authorized to communicate with our API.

Inspecting Console Logs

Now, let’s take a look at the console window of the IdentityServer project:

API call to IdentityServer

What we can see here is that our API sent a request to the /.well-known/openid-configuration/jwks endpoint to retrieve a public key from the identity server to validate our token.

We can validate that this communication is taking place by modifying our token in Postman. If we do that, we are going to get 401 for sure as a result, because the token is tempered with and is valid no more:

Tempered token - IdentityServer4 UI

Excellent. We can see the communication between our API and the Identity Server is working flawlessly.

Inspecting Claims

Finally, we can inspect the claims from the token. To do that let’s add a single code line in the GetCompanies action:

After we acquire a valid token again and send a request to our API, we can see all the claims:

Inspecting claims

So, we can see all the data from the access token provided as a Bearer token in our request. And we can confirm that this token is not tampered with, because at this point, the token is already validated and the API has all the required information from it.

Of course, we’ve used the Client_Credentials flow in this example, but if you use the ResourceOwnerPassword flow, we are going to get additional claims for sure:

Inspecting claims ROP flow

If we decode this token, we are going to get the same result:

Decoded token

Excellent. Everything works as expected.

Conclusion

So, we have learned how to add the UI part to our authorization server and also how to protect our Web API by using two different flows. Of course, we are going to learn more about API protection with additional flows and we are going to use this UI for that purpose as well.

In the next article, we are going to learn how to use the Hybrid flow to protect our web application.

If you have enjoyed reading this article and if you would like to receive the notifications about the freshly published .NET Core content we encourage you to subscribe to our blog.