How to create an IdentityModel TokenResponse object instance for mocking purposes

IdentityModel is an open-source library developed by Dominick Baier and Brock Allen which does an excellent job of simplifying interactions with OAuth 2.0 and OpenID Connect servers.

However, when it comes to unit testing, it can appear on the surface to be somewhat difficult to create certain objects that need to be instantiated on demand for mocking purposes.

The IdentityModel library provides a set of HttpClient extension methods for calling token endpoints, most of which return an instance of the TokenResponse class. At first glance, there doesn’t seem to be a way to set TokenResponse property values, but it isn’t too difficult to work around this once you know how.

In this article, I will demonstrate how to create an instance of the TokenResponse class and populate its properties with mock data that you can use in your unit tests.

Prerequisites

Before getting started, let’s cover a few prerequisites and assumptions that are being made to manage expectations.

First of all, this article assumes that you are already somewhat familiar with the IdentityModel library or that you are currently learning about it and can find out what you need to know about its general usage via the IdentityModel Documentation.

Second, it is assumed that you are already familiar with unit testing and mocking frameworks and can therefore understand the concepts behind why one would need to generate data on demand that is usually returned by a call to an API, as opposed to calling an external service directly in a unit test.

Lastly, you’ll need to have the relevant NuGet packages installed. I recommend the latest version of the IdentityModel NuGet package. Regarding unit testing, my personal preference currently is to use xUnit alongside the Moq mocking framework. However, aside from IdentityModel, your choice of libraries and frameworks does not matter as the focus of this article is on the TokenResponse class, not on how to write unit tests.

Problem analysis

The problem that you’ll inevitably run into when writing unit tests that involve the IdentityModel HttpClient extension methods is the apparent restrictiveness of the TokenResponse class, since most of the extension methods return this type.

The TokenResponse class poses a problem for unit testing since all of its public properties lack setters and there doesn’t appear to be a way to pass values via a constructor or influence the shape of the object after it has been created.

This means that when we create a new TokenResponse object instance and try to set one or more of its properties, we’ll get a compile-time error like the one shown below.

We can't set TokenResponse properties directly
We can’t set TokenResponse properties directly

The above restriction causes issues when writing a unit test that needs to call a method that returns a TokenResponse object, as it appears that the object can’t be transformed into a shape needed to simulate different responses from token endpoints.

Let’s dig into why the TokenResponse properties can’t be set directly. The source code of the TokenResponse class from Version 6.0.0 of the IdentityModel library has been reproduced below for reference.

// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace IdentityModel.Client;

/// <summary>
/// Models a response from an OpenID Connect/OAuth 2 token endpoint
/// </summary>
/// <seealso cref="IdentityModel.Client.ProtocolResponse" />
public class TokenResponse : ProtocolResponse
{
    /// <summary>
    /// Gets the access token.
    /// </summary>
    /// <value>
    /// The access token.
    /// </value>
    public string AccessToken => TryGet(OidcConstants.TokenResponse.AccessToken);

    /// <summary>
    /// Gets the identity token.
    /// </summary>
    /// <value>
    /// The identity token.
    /// </value>
    public string IdentityToken => TryGet(OidcConstants.TokenResponse.IdentityToken);

    /// <summary>
    /// Gets the scope.
    /// </summary>
    /// <value>
    /// The scope.
    /// </value>
    public string Scope => TryGet(OidcConstants.TokenResponse.Scope);
        
    /// <summary>
    /// Gets the issued token type.
    /// </summary>
    /// <value>
    /// The issued token type.
    /// </value>
    public string IssuedTokenType => TryGet(OidcConstants.TokenResponse.IssuedTokenType);
        
    /// <summary>
    /// Gets the type of the token.
    /// </summary>
    /// <value>
    /// The type of the token.
    /// </value>
    public string TokenType => TryGet(OidcConstants.TokenResponse.TokenType);

    /// <summary>
    /// Gets the refresh token.
    /// </summary>
    /// <value>
    /// The refresh token.
    /// </value>
    public string RefreshToken => TryGet(OidcConstants.TokenResponse.RefreshToken);

    /// <summary>
    /// Gets the error description.
    /// </summary>
    /// <value>
    /// The error description.
    /// </value>
    public string ErrorDescription => TryGet(OidcConstants.TokenResponse.ErrorDescription);

    /// <summary>
    /// Gets the expires in.
    /// </summary>
    /// <value>
    /// The expires in.
    /// </value>
    public int ExpiresIn
    {
        get
        {
            var value = TryGet(OidcConstants.TokenResponse.ExpiresIn);

            if (value != null)
            {
                if (int.TryParse(value, out var theValue))
                {
                    return theValue;
                }
            }

            return 0;
        }
    }
}

Notice how the TokenResponse class inherits from the ProtocolResponse class.

All of the properties within the TokenResponse class call the TryGet method defined on the ProtocolResponse base class, which attempts to retrieve the value of the specified field from the underlying JSON content.

The ProtocolResponse class also forms part of the secret for creating TokenResponse class instances with mock data which we’ll find out about shortly.

Untestable code?

Suppose our application is a ‘machine-to-machine’ program and only needs to obtain tokens based on the Client Credentials OAuth 2.0 flow. In this case, we can define a simple interface for our own token client that can retrieve a token based on the specified client credentials, as follows.

using IdentityModel.Client;
 
/// <summary>
/// Token Client interface.
/// </summary>
public interface ITokenClient
{
    #region Methods
 
    Task<TokenResponse> GetTokenResponseAsync(ClientCredentialsTokenRequest request);
 
    #endregion
}

We can then create a class that implements the ITokenClient interface and has the responsibility of getting tokens from the server. The GetTokenResponseAsync method does this by delegating to the appropriate IdentityModel HttpClient extension method, i.e. RequestClientCredentialsTokenAsync.

using IdentityModel.Client;
 
/// <summary>
/// Implements the retrieval logic for tokens.
/// </summary>
public class TokenClient : ITokenClient
{
    #region Readonlys
 
    private readonly HttpClient _httpClient;
 
    #endregion
 
    #region Constructor
 
    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="httpClient">The HTTP Client</param>
    public TokenClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
 
    #endregion
 
    #region Methods
 
    /// <summary>
    /// Gets a Token Response from the server.
    /// </summary>
    /// <param name="request">The Client Credentials Token Request</param>
    /// <returns><see cref="TokenResponse"/></returns>
    public async Task<TokenResponse> GetTokenResponseAsync(ClientCredentialsTokenRequest request)
    {
        return await _httpClient.RequestClientCredentialsTokenAsync(request);
    }
 
    #endregion
}

To write a unit test that can call GetTokenResponseAsync we’ll need to find a way to mock this method. Otherwise, the test would be making a real API call to a token endpoint and it wouldn’t be a unit test anymore!

But how can we set up a mock when it isn’t possible to populate the properties of a TokenResponse object directly?

That’s where the ProtocolResponse class comes in.

ProtocolResponse to the rescue

The ProtocolResponse class contains a couple of static factory methods; one of which is named FromHttpResponseAsync. This method takes a HttpResponseMessage object as an input parameter and generates a response from this. You can see the method in action below.

using IdentityModel.Client;
using System.Net;
 
var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK);
var tokenResponse       = await ProtocolResponse.FromHttpResponseAsync<TokenResponse>(httpResponseMessage);

In the above code, a HttpResponseMessage object is first created with an OK status code. The FromHttpResponseAsync method is then called, passing in the HttpResponseMessage instance and specifying the response type to return as TokenResponse.

This doesn’t quite do the job though, remember the TryGet method calls within the TokenResponse class? The above code isn’t going to generate the JSON content needed for the TryGet method to succeed in returning values for the TokenResponse properties such as AccessToken and Scope.

Content creation

As it turns out, we can update the code such that it creates the required JSON content quite easily. We do this by setting the Content property of the HttpResponseMessage object with the result of a call to the static JsonContent.Create method, as shown in the updated code sample below.

using IdentityModel.Client;
using System.Net;
using System.Net.Http.Json;
 
var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
    Content = JsonContent.Create(new
    {
        access_token = "token",
        expires_in   = 3600
    })
};
 
var tokenResponse = await ProtocolResponse.FromHttpResponseAsync<TokenResponse>(httpResponseMessage);

The above code passes an anonymous object containing properties that are named according to the constants that are defined within the IdentityModel OidcConstants.TokenResponse class.

After creating a TokenResponse object using the above code, the AccessToken and ExpiresIn properties will return the values that have been specified within the JSON content of the HttpResponseMessage object.

Going further

We can take things a step further by creating a class that will hold the content we want to serialise and store as the JSON content for the response. The class below shows the implementation of this for reference.

using IdentityModel;
using System.Text.Json.Serialization;
 
/// <summary>
/// Models the content of a response from an OpenID Connect / OAuth 2 token endpoint.
/// </summary>
public class TokenResponseContent
{
    #region Properties
 
    /// <summary>
    /// The access token.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.AccessToken)]
    public string? AccessToken { get; set; }
 
    /// <summary>
    /// The identity token.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.IdentityToken)]
    public string? IdentityToken { get; set; }
 
    /// <summary>
    /// The scope.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.Scope)]
    public string? Scope { get; set; }
 
    /// <summary>
    /// The issued token type.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.IssuedTokenType)]
    public string? IssuedTokenType { get; set; }
 
    /// <summary>
    /// The type of the token.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.TokenType)]
    public string? TokenType { get; set; }
 
    /// <summary>
    /// The refresh token.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.RefreshToken)]
    public string? RefreshToken { get; set; }
 
    /// <summary>
    /// The error description.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.ErrorDescription)]
    public string? ErrorDescription { get; set; }
 
    /// <summary>
    /// The expires in.
    /// </summary>
    [JsonPropertyName(OidcConstants.TokenResponse.ExpiresIn)]
    public int ExpiresIn { get; set; }
 
    #endregion
}

The above class is very similar to the original TokenResponse class, as it has all of the same properties. However, the properties now have public setters and have been decorated with a JsonPropertyName attribute so that when the class is serialised the property names will match what the TryGet method that was mentioned previously is expecting.

With the TokenResponseContent class defined, we can now create a simplified helper method where the details of how TokenResponse objects are created is hidden from view.

/// <summary>
/// Creates a <see cref="TokenResponse"/> object on demand.
/// </summary>
/// <param name="statusCode">The HTTP status code of the response</param>
/// <param name="tokenResponseContent">The response content</param>
/// <returns><see cref="TokenResponse"/></returns>
public static async Task<TokenResponse> CreateTokenResponseAsync(
    HttpStatusCode statusCode,
    TokenResponseContent tokenResponseContent)
{
    var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = JsonContent.Create(tokenResponseContent)
    };
 
    return await ProtocolResponse.FromHttpResponseAsync<TokenResponse>(httpResponseMessage);
}

This helper method can now be called from unit tests to create TokenResponse objects on demand.

Since the TokenResponseContent class wraps the main properties that we need to serialise as content, the above implementation only requires two parameters to be specified, which will help to simply unit test setup code.

We can use the helper method in place of the code that was shown previously, as per the code sample below.

using IdentityModel.Client;
using System.Net;
using System.Net.Http.Json;
 
var tokenResponseContent = new TokenResponseContent
{
    AccessToken = "token",
    ExpiresIn   = 3600,
Scope = "api" }; TokenResponse tokenResponse = await CreateTokenResponseAsync(HttpStatusCode.OK, tokenResponseContent);

The TokenResponseContent class allows us to simulate a variety of different responses by setting the relevant property values. For example, we could set the Error property which would cause the IsError property on the TokenResponse object to return true, simulating an unauthorised token request.

Mocking

If you are using a mocking framework such as Moq you can set up mocks that return TokenResponse objects using the helper method defined in the previous section.

The code sample below demonstrates a quick example of this in action (using statements omitted).

var tokenResponse = await CreateTokenResponseAsync(HttpStatusCode.OK, new TokenResponseContent
{
    AccessToken = "token",
    ExpiresIn   = 3600
});
 
var tokenRequest = new ClientCredentialsTokenRequest
{
    Address      = "https://demo.duendesoftware.com/connect/token",
    ClientId     = "id",
    ClientSecret = "secret"
};
 
var tokenClientMock = new Mock<ITokenClient>();
tokenClientMock.Setup(c => c.GetTokenResponseAsync(tokenRequest)).ReturnsAsync(tokenResponse);

When using Moq, you can get a mock ITokenClient instance by accessing the Value property of the Mock object. This object instance can then be passed to any objects that need it so that unit tests can be implemented.

With all of the above in place, any tests that call the GetTokenResponseAsync method (either directly or indirectly) can now run reliably and you can set up different mocks to simulate both successful and unsuccessful responses from the token server.

Summary

In this article, I have shown how you can create an instance of the IdentityModel TokenResponse class and populate its internal content for the purposes of mocking when writing unit tests.

I first looked at the specifics of the problem and demonstrated why at a first glance the TokenResponse class doesn’t appear to make it easy to set things up for unit testing.

I then walked through how you can resolve the problem by using the ProcotolResponse.FromHttpResponseAsync method and at the same time generate the JSON content that is needed to simulate the responses that can be returned by a token server.

I finished by providing a quick example of how to mock the return value of the custom GetTokenResponseAsync method.

Assuming you already know how to write effective unit tests, I trust that you will have found this article helpful for getting you past the initial hurdle of how to create TokenResponse object instances with suitable property values. For those of you who aren’t currently familiar with writing unit tests, that will be a topic for another day!


I hope you enjoyed this post! Comments are always welcome and I respond to all questions.

If you like my content and it helped you out, please check out the button below 🙂

Comments

Morten

I was struggling with this exact thing, so this article was incredibly helpful. Thank you!

April 12, 2023

Jonathan Crozier

Hi Morten, thanks for the comment. I’m very pleased you found the article helpful 😀

April 12, 2023