jozolo
jozolo

Reputation: 367

Unit Testing a JWT Token with Web API

I am trying to use Web API2, JWT, Microsoft.IdentityModel.JsonWebTokens 5.2.422 and the token validation logic as outlined in this article: http://www.decatechlabs.com/secure-webapi-using-jwt

Everything works great for my project when I repeat the steps in the article, including testing the API via Restlet. However, I am trying to use Test Driven Development (TDD) for this project, and I’d ideally like to test that everything works in my tests, including the token validation handler. I am able to test my Controllers if I call them directly in my unit tests, but that is bypassing the actual token validation handler. So, I tried using self-hosted HTTP to properly exercise the complete API, including all of the token validation handler logic. Here is my complete unit test to get a token and then pass the token to a second method requiring authorization:

[TestMethod]

public void GetAuthorizedStatus_SelfHostedHTTP()
{
    HttpServer server = TestAPIHelper.GenerateTestServer();

    using (HttpMessageInvoker client = new HttpMessageInvoker(server))
    {
        string token = string.Empty;

        using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, loginURL))
        {
            var stringContent = new StringContent(JsonConvert.SerializeObject(TestAPIHelper.loginObject), Encoding.UTF8, "application/json");
            request.Content = stringContent;

            using (HttpResponseMessage response = client.SendAsync(request, System.Threading.CancellationToken.None).Result)
            {
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Error getting token from login portion");

                token = response.Content.ReadAsAsync<string>().Result;
                Assert.IsTrue(token.Length > 50);
            }
        }

        using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, authorizedStatusURL))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

            using (HttpResponseMessage response = client.SendAsync(request, System.Threading.CancellationToken.None).Result)
            {
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Error getting status from Authenticated portion.");
            }
        }
    };
}

The problem is that the TokenValidationHandler throws an "Object reference not set to an instance of an object." exception on the second of the below two lines of the handler, only when called by my unit test with the token attached. If I trigger the handler using Restlet/Postman/whatever, no exception is thrown and everything works fine.

Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);

I don’t understand what is causing only the second line to error when the first, nearly identical line works - both lines call the same method. And I don’t understand why it works with third party software but doesn’t work with my test code - my concern is that if I don't figure this out for unit testing, then I won't get the code working for the real application calling this api. I assume it is either some trivial setting in my test code that I need to add to my request before submitting. But perhaps I need to architect a completely different method of calling the API in my unit tests.

Upvotes: 7

Views: 9239

Answers (1)

Andrei Dragotoniu
Andrei Dragotoniu

Reputation: 6335

I wouldn't do this.

What I did in situations like this is write integration tests that covered the token logic.

This means calling the token endpoint, retrieving a token, then calling something else and seeing what happens.

You can then add other tests, like what happens when the token is missing, or is invalid, or has expired, or includes the wrong claims.

Upvotes: 0

Related Questions