AspNetCore.TestHost + Azure Active Directory (Part I)
I have been evaluating new practices for implementing Integration Testing WebAPIs and I’ve been trying to use TestHost to test a WebAPI that I have secured with Azure Active Directory. I am able to use PostMan to obtain a bearer token from Azure AD’s oauth2/token endpoint and call HTTP GET on ‘/api/Values’. However, when I do the same to the TestHost Server I always get a 401 unauthorized error.
I’ve configured my TestHost to use the Startup class that is built into my ASP.NET Core WebAPI project (it’s the one that is generated by default when you use the standard template and select Azure Active Directory as your authentication provider).
Server = new TestServer(
new WebHostBuilder()
.UseStartup<Startup>()
);
I’ve tried two methods of attaching the bearer token.
First approach, using the DefaultRequestHeaders of the client I generate from the TestServer:
Client = Server.CreateClient();
Client.DefaultRequestHeaders.Add("Authorization", "Bearer " + AccessToken);
Second approach is attaching the header to the request itself:
var req = _sut.Server.CreateRequest("/api/Values")
.AddHeader("Authorization", "Bearer " + _sut.AccessToken);
var response = await req.GetAsync();
However, both of these get a 401 unauthorized.
I am using the same method to obtain a token as I do in PostMan, except in code in my automated unit tests.
public static string GetAccessToken()
{
string token = null; // Constants
var tenant = "MY_TENANT_HERE.onmicrosoft.com";
var serviceUri = "https://MY_TENTANT_HERE.com/WebApplicationAAD";
var clientID = "a1d51587-bf4c-4915-b588-8df1d9fd7ac9"; // this is the Application ID for the Native App in Azure AD
var userName = "integration_test@MY_TENANT_HERE.com";
var password = "THE_PASSWORD_FOR_THE_TEST_ACCOUNT";
var appClientId = "d476fd33-4cfc-4aeb-9d4d-ea4978af5660"; // this is the Application ID for the Web API app in Azure AD
using (var webClient = new WebClient())
{
var requestParameters = new NameValueCollection();
requestParameters.Add("grant_type", "password");
requestParameters.Add("client_id", clientID);
requestParameters.Add("username", userName);
requestParameters.Add("password", password);
requestParameters.Add("resource", appClientId);
//requestParameters.Add("scope", "openid");
var url = $"https://login.microsoftonline.com/" + tenant + "/oauth2/token";
var responsebytes = webClient.UploadValues(url, "POST", requestParameters);
var responsebody = Encoding.UTF8.GetString(responsebytes);
var jsonresult = JObject.Parse(responsebody); token = (string)jsonresult["access_token"];
}
return token;
}
This code produces a token. It is producing the same postman post that I am doing.
Doing HTTP GET on the IIS Express hosted WebAPI using the same technique WORKS.
I suspect either AspNetCore.TestHost does not support this or I am not doing something to properly configure it to light up the Azure Active Directory config that is working when I debug on IIS Express but documentation is extremely light.
In Part II, I’ll show you how I overcame this challenge and why I was ultimately seeing this behavior.