Protect Web API using IdentityServer4 and consume with Blazor
Tags: csharp, webdev, tutorial, dotnet
Published: 2019-12-12 19:58:08

---
title: Protect Web API using IdentityServer4 and consume with Blazor
published: true
date: 2019-12-12 19:15:00 UTC
tags: csharp, webdev, tutorial, dotnet
canonical_url: https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/
---
[Original Article](https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/)

In the previous tutorial, you created a public web API and learned the [right way to access it](https://wellsb.com/csharp/aspnet/blazor-httpclientfactory-and-web-api/) from a server-side Blazor application. In this tutorial, you will make that web API private by securing it using IdentityServer4. Specifically, you will restrict access to the API to only select applications that are authenticated via a secret key. For example, you may want your API to be accessible from your company’s mobile application or website, but you do not want it to be public to the outside world.

**In this Blazor tutorial series**
- [Part 1: Blazor with Web API Solution Structure](https://wellsb.com/csharp/aspnet/blazor-httpclientfactory-and-web-api/)
- Part 2: Consume API protected by IdentityServer4
- Part 3: Cache IdentityServer4 API Access Token (_Coming Soon_)

Either follow the tutorial about [using HttpClientFactory to access an external web API](https://wellsb.com/csharp/aspnet/blazor-httpclientfactory-and-web-api/), or clone the previous tutorial’s [GitHub repo](https://github.com/bradwellsb/blazor-contacts/tree/tutorial-part1) to get caught up.

## Create IdentityServer4 Authentication Server

To create the auth server, you will use IdentityServer4. Install the relevant Nuget packages by issuing the following commands in the Package Manager Console or in a PowerShell terminal.

```
Install-Package IdentityServer4
Install-Package IdentityServer4.Templates
```

Recall, in this series we are creating a contact management application using Blazor. Open the **BlazorContacts** solution in Visual Studio. In the Solution Explorer, right click the solution and select **Open in File Explorer**.

With the root solution folder open in your file explorer, you should see a BlazorContacts.API directory, a BlazorContacts.Shared directory, and a BlazorContacts.Web directory among other files and folders. Create a new folder called **BlazorContacts.Auth**.

Navigate to the new BlazorContacts.Auth folder in a PowerShell terminal and run the following command to scaffold a new IdentityServer4 empty template.

```
dotnet new is4empty
```

Once the template is created, you must add the new project to your existing BlazorContacts solution in Visual Studio. Right-click the solution and **Add \> Existing Project…** Find the BlazorContacts/BlazorContacts.Auth folder you created and select the **BlazorContacts.Auth.csproj** file.

Your **BlazorContacts.Auth** project is templated with an empty **Config.cs** file that looks like the following:

```csharp
using IdentityServer4.Models;
using System.Collections.Generic;
 
namespace BlazorContacts.Auth
{
    public static class Config
    {
        public static IEnumerable<IdentityResource> Ids =>
            new IdentityResource[]
            { 
                new IdentityResources.OpenId()
            };
 
        public static IEnumerable<ApiResource> Apis =>
            new ApiResource[] 
            { };
        
        public static IEnumerable<Client> Clients =>
            new Client[] 
            { };
        
    }
}
```

## Configure IdentityServer4 Auth Server

In **Config.cs** , you will list the APIs you wish to secure, as well as any approved clients, such as a web front-end or a mobile application.

Start by adding a new API resource to the `Apis` enumerable, and give it a name.

```csharp
public static IEnumerable<ApiResource> Apis =>
    new ApiResource[] 
    {
        new ApiResource("blazorcontacts-api")
    };
```

Next, list any approved clients by adding them to the `Clients` array.

```csharp
public static IEnumerable<Client> Clients =>
    new Client[] 
    {
        new Client
        {
            AllowedGrantTypes = GrantTypes.ClientCredentials,
			ClientId = "blazorcontacts-web",
            ClientSecrets =
            {
                new Secret("thisismyclientspecificsecret".Sha256())
            },
            AllowedScopes = { "blazorcontacts-api" }
        }
    };
```

The `AllowedGrantTypes` line indicates that authentication is performed using client credentials. That is to say that the combination of client ID and a secret key are used to authenticate the client application itself to the auth server. Next, you defined the ClientID and Secret that will be used to authenticate your Blazor application. Finally, the `AllowedScopes` line indicates that this particular client should have access to the `blazorcontacts-api` API that was previously defined.

**Note** : It is important to use secure keys and to securely hash them. It is never a good idea to include secrets directly in your application’s source code. In another tutorial, you will learn a more secure technique for including sensitive data in your projects.

## Configure API

With the authentication server set up, it will issue access tokens to the client, authorizing it to access interfaces within its allowed scopes. You now need to configure the web API and clients, themselves. The API should operate as `blazorcontacts-api`, as defined in Config.cs of BlazorContacts.Auth.

Install and reference the `Microsoft.AspNetCore.Authentication.JwtBearer` package for the BlazorContacts.API project. Then, open the **Startup.cs** file of BlazorContacts.API and locate the ConfigureServices() method. Here, you will configure the authentication service of the API.

```csharp
services.AddAuthentication("Bearer")
  .AddJwtBearer("Bearer", options =>
  {
      options.Authority = "http://localhost:5000";
      options.RequireHttpsMetadata = false;
 
      options.Audience = "blazorcontacts-api";
  });
```

The above code connects a JWT bearer (###Define###) with issuing authority of http://localhost:5000. This should correspond to the address of BlazorContacts.Auth server. In this test environment, we are not using SSL certificates, but feel free to require them in your production application. Finally, the `Audience` should correspond to the name you assigned to the API resource when you added it to the Auth server’s `Apis` array. In this case, we are using `blazorcontacts-api`.

With the service configured, you must actually start the service by adding it to the `ServiceCollection` container. In the `Configure()` method of Startup.cs (still within BlazorContacts.API), add the following lines:

```csharp
app.UseAuthentication();
app.UseAuthorization();
```

Now, any controller in the API can be forced to require authorization by simply adding a `[Authorize]` annotation to the appropriate class.

For example, the **ContactsController.cs** controller file contained a class with methods to GET, POST, PUT, and DELETE contacts. To require authorization to access these API methods, start by including the following namespace.

```csharp
using Microsoft.AspNetCore.Authorization;
```

This enables you to use the `[Authorize]` annotation. Next, annotate parts of the API that you wish to protect. You could use tag for individual methods, or for the entire class. You could restrict access to the entire ContactsController class by adding the `[Authorize]` tag above the class definition:

```csharp
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ContactsController : ControllerBase
{
...
}
```

Remember, the authorization technique you have configured does not require individual user login to consume the API; instead, it ensures that the clients attempting to access the API are using a valid CliendID/Secret pair. Now, you simply need to configure your Blazor web app to use the client ID and secret key you allowed when setting up the Authentication server.

## Configure Blazor Web App

When attempting to make an API call that requires authorization, the web app must include an access token in the header of the request. This access token, issued by the authentication server, will contain the unique client ID and secret key. When the API receives an access request, it will check that the access token exists, and confirm its authenticity with the authentication server before repsonding to the request.

To begin this handshaking procedure, modify the **ApiService.cs** file of the **BlazorContacts.Web** project that you created in the last tutorial. You will need to include in your BlazorContacts.Web project a package reference for the `IdentityModel` package. Then, add a method to fetch an access token from the auth server. The most basic form for this feature would be the following, though it would be wise to add some error handling. See the [source code](https://github.com/bradwellsb/blazor-contacts/tree/tutorial-part2) for a more robust version of this method.

```csharp
private async Task<string> requestNewToken()
{
    var discovery = await HttpClientDiscoveryExtensions.GetDiscoveryDocumentAsync(
        _httpClient, "http://localhost:5000");
 
    var tokenResponse = await HttpClientTokenRequestExtensions.RequestClientCredentialsTokenAsync(_httpClient, new ClientCredentialsTokenRequest
    {
        Scope = "blazorcontacts-api",
        ClientSecret = "thisismyclientspecificsecret",
        Address = discovery.TokenEndpoint,
        ClientId = "blazorcontacts-web"
    });
 
    return tokenResponse.AccessToken;
}
```

The variable `discovery` uses the instance of HttpClient created by the HttpClientFactory and sets an endpoint for the authentication server. This endpoint should correspond to the base address of the authentication server. It is used to fetch an access token for the scoped API, using the client ID of the Blazor web app and the secret key set in **Config.cs** of the BlazorContacts.Auth project.

Note: In a production project, you should never include values such as ClientId and ClientSecret directly in the source code. In another tutorial, you will learn how to securely pull secret values into your project.

To make a call to an API requiring authorization, you must use the string returned by `RequestNewToken()` and then set that string as the bearer token of the instance of HttpClient that is attempting to consume the API.

```csharp
var access_token = await requestNewToken();
_httpClient.SetBearerToken(access_token);
```

The `GetContactsAsync()` method, for example, might look like the following:

```csharp
public async Task<List<Contact>> GetContactsAsync()
{
    var access_token = await requestNewToken();
    _httpClient.SetBearerToken(access_token);
 
    var response = await _httpClient.GetAsync("api/contacts");
    response.EnsureSuccessStatusCode();
 
    using var responseContent = await response.Content.ReadAsStreamAsync();
    return await JsonSerializer.DeserializeAsync<List<Contact>>(responseContent);
}
```

This technique works, but it requests a new access token for every API call. This puts an unnecessary load on the authentication server. In another tutorial, you will learn how to cache the access token for a defined period of time to maximize efficiency.

## Putting it all together

To test your application, don’t forget the **Debug \> Set Startup Projects** dialog should be configured for **Multiple startup projects** , and BlazorContacts.Auth, BlazorContacts.API, and BlazorContacts.Web should all be set to **Start**.

Once you run the program and navigate to the Contacts page, an access token will be fetched and your Blazor application will be authorized to consume the web API and list all contacts.

In this tutorial, you learned how to secure a Web API and access it from a Blazor server-side application using HttpClientFactory. You also learned how to grant API access to specific front-end applications, such as web or mobile apps. The techniques you learned in this tutorial can be extended to other ASP.NET web apps, including the MVC and Razor Pages framework. Finally, this authentication approach has the added benefit of still being able to use another authorization technique, such as Azure AD B2C, to provide individual user authorization on the front-end of your application.

In the coming tutorials, you will also learn how to add caching to this project to reduce unnecessary access token requests to the authentication server. You will also learn how to securely pull secret keys and other sensitive values into your project.

The source code for this project is [available on GitHub](https://github.com/bradwellsb/blazor-contacts/tree/tutorial-part2).

[Original Article](https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/)