---
title: "ASP.NET Core 6 - JwtBearer library: what’s new?"
description: "What changed in the ASP.NET Core JwtBearer library from 3.1 to 6: MapInboundClaims, a custom back-channel HttpClient, refresh intervals and token validation."
url: https://nestenius.se/net/asp-net-core-jwtbearer-library-whats-new/
date: 2022-02-04
author: "Tore Nestenius"
category: ".NET"
site: https://nestenius.se/
---

# ASP.NET Core 6 - JwtBearer library: what’s new?

As a developer and trainer, it is hard to keep up with all the changes in all the libraries. In this blog post, I will summarize the recent key changes that I have found in the ASP.NET Core JwtBearer library versions 3.1.22, 5.0.13, and 6.0.1.

The JwtBearer library is distributed in the [Microsoft.AspNetCore.Authentication.JwtBearer](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer/) NuGet package. The corresponding source code can be found in the [/src/Security/Authentication/](https://github.com/dotnet/aspnetcore/tree/main/src/Security/Authentication) folder in the [ASP.NET Core repository](https://github.com/dotnet/aspnetcore) on GitHub. 

## What is the purpose of the ASP.NET Core JwtBearer library?

The library is implemented as an ASP.NET Core request pipeline middleware, and its sole purpose is to authenticate incoming requests. It will look for JW bearer tokens in the request and, if a token is found, validate it and create a ClaimsPrincipal User instance. The authorization handler can then authorize the user to get access to the requested resource.  

![Diagram showing JwtBearer Handler authenticating an HTTP request with Bearer token and creating a ClaimsPrincipal User](https://nestenius.se/_astro/asp-net-core-jwtbearer-handler-authentication-flow.CnZWbTLS_Zj6bGE.webp)

## What runtime does each version target?

The different versions of the JwtBearer NuGet package target different runtimes:

- Version 3.x.x targets .NET Core 3.1
- Version 5.x.x targets .NET 5.x
- Version 6.x.x targets .NET 6.x

That sounds obvious and logical, but the annoying thing with Visual Studio (as of today) is that, even if you have a .NET Core 3.1 application, it still tells you that version 6 is available, even though it should know that version 6.x.x is not compatible with your current project:  

![Visual Studio NuGet package manager showing Microsoft.AspNetCore.Authentication.JwtBearer update from 3.1.22 to 6.0.1](https://nestenius.se/_astro/visual-studio-nuget-jwtbearer-update-3-1-22-to-6-0-1.0D1XOIGw_2rhzyw.webp)

As a good developer, you want to keep your packages up to date, but trying to update it will result in the following error:  

![NuGet package update error when trying to install an incompatible JwtBearer version](https://nestenius.se/_astro/nuget-jwtbearer-incompatible-version-error.DREFwMtr_Z4cxp8.webp)

This sure is a bit annoying 🙄

## Comparing the editions of JwtBearer

To do the research, I really like to get down to the true source, and the best source is of course the ASP.NET source code. So I downloaded it for the three different versions and then compared the result using [Araxis merge](https://www.araxis.com/merge/). I could have done the same comparisons using [NDepend](https://www.ndepend.com/), but I chose to use Araxis merge because it gave me the best overview for this blog post. Using Araxis merge I can compare all three versions at the same time as shown below:

![Araxis Merge three-way folder and file diff comparing JwtBearerHandler across ASP.NET Core 3.1, 5.0 and 6.0](https://nestenius.se/_astro/araxis-merge-jwtbearer-handler-three-way-diff.BrEc7DZ4_Z1v1aWh.webp)

The interesting source code for the authentication handlers in ASP.Net Core is found in the [/src/Security/Authentication/](https://github.com/dotnet/aspnetcore/tree/main/src/Security/Authentication) directory on GitHub.

## What has changed between the revisions of JwtBearer?

There are, of course, plenty of small changes in this library, and many of the changes consist of added XML comments and improved support for non-nullable reference types.  

But let’s look at the ones that actually matter for us using this library:

### **Map inbound claims option**

This feature, which was introduced in version 5, allows us to very easily disable one of the most annoying features in the .NET authentication stack, and that is the automatic renaming of some of the claims found in the token.

The flag is by default set to true, but can now easily be disabled using:

```csharp
services.AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.MapInboundClaims = false;
        //...
    });
```

Let's compare the result when this flag is false or true. If we send the following **access token** in a request to the library:

```json
{    
    "nbf": 1642960856,
	"exp": 1642964456,
	"iss": "https://localhost:6001",
	"aud": "paymentapi",
	"client_id": "client",
	"managment": "yes",
	"email": "tn@tn-data.se",
	"name": "tore nestenius",    
	"role": [ "admin", "developer", "support" ],  
	"website": "https://www.tn-data.se",    
	"jti": "9320D007CFA6EF1C21ACA09908216BC7",    
	"iat": 1642960856,    
	"scope": [ "payment" ]
```

Then the resulting **ClaimsPrincipal** User will contain the following set of claims:

**MapInboundClaims = false**

```text
Claims 
 - nbf=1642960856
 - exp=1642964456
 - iss=https://localhost:6001
 - aud=paymentapi
 - client_id=client
 - managment=yes
 - email=tn@tn-data.se
 - name=tore nestenius
 - role=admin
 - role=developer
 - role=support
 - website=https://tn-data.se
 - iat=1642960856
 - scope=payment
```

**MapInboundClaims = true**

```text
Claims
 - nbf=1642961012
 - exp=1642964612
 - iss=https://localhost:6001 
 - aud=paymentapi
 - client_id=client
 - managment=yes
 - http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress=tn@tn-data.se
 - name=tore nestenius
 - http://schemas.microsoft.com/ws/2008/06/identity/claims/role=admin
 - http://schemas.microsoft.com/ws/2008/06/identity/claims/role=developer
 - http://schemas.microsoft.com/ws/2008/06/identity/claims/role=support
 - http://schemas.xmlsoap.org/ws/2005/05/identity/claims/webpage=https://tn-data.se
 - iat=1642961012
 - scope=payment
```

I have answered questions about claims mapping on [Stack Overflow](https://stackoverflow.com/users/68490/tore-nestenius) for quite some time now and I wish this flag was set to false by default. This would have made life so much easier for developers working with claims.

### **Customizing the JwtBearer back channel HttpClient**

The JwtBearer will, via the Configuration Manager, make HTTP(s) requests to our identity provider through the back channel. For example, it will use this channel to download the **openid-configuration** and the **public keys** from the authorization provider (for example [IdentityServer](https://duendesoftware.com/)).

![Diagram showing JwtBearer Handler with ConfigurationManager using HttpClient and Backchannel HttpHandler to fetch OpenID conf](https://nestenius.se/_astro/jwtbearer-handler-configuration-manager-backchannel-identity.BFhiEWqR_Zt7Nui.webp)

Before version 6, we could provide our own **HttpMessageHandler** to customize the BackChannel request and response, by for example:

```csharp
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(opt =>
    {
        opt.BackchannelHttpHandler = new MyBackChannelListener();
        //...
    };
```

 Why would you want to provide your own? Some of the use-cases can be:

- Improve logging of the backchannel requests
- Add custom headers to the outgoing request
- Inspect the response
- Implement automatic retry when a request fails, perhaps using the [Polly Project library](https://github.com/App-vNext/Polly).

In version 6 they also introduced the option to provide your own **HttpClient** instance. This was added as a response to GitHub [issue #27426](https://github.com/dotnet/aspnetcore/issues/27426).

This allows us to provide our own client like this:

```csharp
builder.Services.AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Backchannel = new HttpClient()
        {
            //Custom client options
        };
    });
```

Why would you want to provide your own client?

- Work with the **HttpClientFactory**
- Better control of the **HTTP protocol** to be used  
    (i.e., only use HTTP/2 or HTTP/1.1)

Some related resources

- [Use IHttpClientFactory in RemoteAuthenticationOption](https://github.com/dotnet/aspnetcore/issues/10542)
- [Add HttpClient Backchannel property to JwtBearerOptions](https://github.com/dotnet/aspnetcore/pull/27572)

### **Customizing the configuration refresh intervals**

In .NET 5 they introduced two new options to control the backchannel refresh intervals and you define them in code using:

```csharp
 services.AddAuthentication().AddJwtBearer(options =>
 {
     //.NET 5 defaults        
	 options.AutomaticRefreshInterval = new TimeSpan(1, 0, 0, 0);   //24 hours        
	 options.RefreshInterval = new TimeSpan(0, 0, 0, 30);           //30 seconds

     //.NET 6 defaults
     options.AutomaticRefreshInterval = new TimeSpan(0, 12, 0, 0);  //12 hours      
	 options.RefreshInterval = new TimeSpan(0, 0, 5, 0);            //5 minutes   
});
```

In .NET 6 they changed the default values as shown above, but the main question is of course, what do they control?

### **Automatic refresh interval**

This parameter will control how often it will download and refresh the cached **openid-configuration** and the **JWKS** signing keys. 

### **Refresh interval**

If a back channel request to the identity provider fails, then this value will control the wait time between retries. If it fails to refresh the configuration, then it will keep using the existing configuration that was retrieved earlier.

## JwtBearer Dependencies

The JwtBearer also depends on a few other libraries, which are:

![Diagram showing JwtBearer dependency on Microsoft.IdentityModel.Protocols.OpenIdConnect, which depends on Microsoft.IdentityM](https://nestenius.se/_astro/jwtbearer-identitymodel-openidconnect-dependency-diagram.BiLnw5Uh_Z1P8usz.webp)

These three libraries are all located in a different repository named [azure-activedirectory-identitymodel-extensions-for-dotnet](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet). It is not located under the ASP.NET Core, instead it is located under the 
[AzureAD](https://github.com/AzureAD) organization. 

The versioning of these packages does not follow the same versioning pattern as ASP.NET Core does, so in my investigation, I used the following versions:

- ASP.NET Core 3.1 -> JwtBearer (3.1.22) -> …OpenIDConnect (5.5.0)
- ASP.NET 5.0-> JwtBearer (5.0.13) -> …OpenIDConnect (6.7.1)
- ASP.NET 6.0 -> JwtBearer (6.0.1) -> …OpenIDConnect (6.10.0)

Naturally there have been numerous improvements here too, but for those of us who are working with APIs, the **TokenValidationParameters** is the most interesting one for us.

```csharp
services.AddAuthentication().AddJwtBearer(options =>
{
    //For example      
	options.TokenValidationParameters.ValidateIssuer = false;
    ...
}    
```

What interesting changes are here? If we compare version 5.5.0 with 6.10.0, we see that some of the most interesting changes are the following:

- #### New validation delegates

    - **AlgorithmValidator**  
        By providing a custom delegate to this parameter, you can do your own validation of the cryptographic algorithm used. If provided, then the valid algorithms provided in the ValidAlgorithms parameter will be ignored. Discussions about this delegate can be found in [the GitHub pull request](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1413).
    - **TypeValidator**By providing a custom delegate to this parameter, you can do your own token type validation instead of the built-in default one. Discussions about this delegate can be found in [Issue 1378](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1378) and [Issue #1385](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1385)

- #### New properties

    - **IgnoreTrailingSlashWhenValidatingAudience**  
        Setting this property will control if a '/' is significant at the end of the audience or not. (default true)
    - **TryAllIssuerSigningKeys**Will control whether all the signing keys should be tried during signature validation when the referred key in the token is not found. (default true)
    - **ValidAlgorithms**  
        Contains a list of the valid algorithms for cryptographic operations.
    - **ValidTypes**  
        Contains a list of the valid token types.

## Conclusion

Keeping up with all the changes in the .NET stack is hard and using [Araxis merge](https://www.araxis.com/merge/) allowed me to quickly compare three versions of the code base at the same time. The most annoying thing when dealing with the authentication stack is that the code involved is located in two different repositories and it is really annoying that the code in the AzureAD repository is not covered by [https://source.dot.net/](https://source.dot.net/), which otherwise is very handy when searching the Microsoft code base. 

When I create my training materials I often do dive deep into the .NET source code, and looking under the hood gives you another perspective on how things actually work and the amazing work the .NET developers put into the stack!

While browsing the source code I found some inaccuracies in the code XML comments, so I filed [an issue to the ASP.NET Core team on GitHub](https://github.com/dotnet/aspnetcore/issues/39725) and it was quickly resolved within a few days. 

I have built training courses about this topic and it has helped several companies move forward with their journey. Check out [my training courses](https://tn-data.se/courses/).

## More posts by the author
- [What's new in ASP.NET Core authentication in .NET 11](https://nestenius.se/net/whats-new-in-asp-net-core-authentication-in-net-11/)

- [Debugging OpenID Connect claim problems in ASP.NET Core](https://nestenius.se/net/missing-openid-connect-claims-in-asp-net-core/)
- [ASP.NET Core JwtBearer library: what’s new?](https://nestenius.se/net/asp-net-core-jwtbearer-library-whats-new/)

## Related Training Workshops

- [Building ASP.NET Core APIs](https://tn-data.se/courses/building-asp-net-core-apis/)
- [ASP.NET Core fundamentals](https://tn-data.se/courses/asp-net-core-fundamentals/)
