2
votes

I'm attempting to access an API App I have hosted on Azure and secured with Azure AD.

For the API App I've set App Service Authentication = Azure Active Directory "Express" management mode.

In the "classic" portal I've created a couple of applications under AD. One for the API App and another for the Web App. And for the Web App I've added an entry under "permissions to other applications" for the API App (though I'm not sure I need this as "user assignment required to access app" is off for the API App). I've also generated a key for the Web App.

Following the example code given here - https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-oauth2-appidentity ...

I can successfully obtain a bearer token using the following code:

private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string appKey = ConfigurationManager.AppSettings["ida:AppKey"];

static string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);

private static string ApiId = ConfigurationManager.AppSettings["ApiId"];

private static AuthenticationContext authContext = new AuthenticationContext(authority);
private static ClientCredential clientCredential = new ClientCredential(clientId, appKey);

...

AuthenticationResult result = null;
int retryCount = 0;
bool retry = false;

do
{
    retry = false;
    try
    {
        // ADAL includes an in memory cache, so this call will only send a message to the server if the cached token is expired.
        result = await authContext.AcquireTokenAsync(ApiId, clientCredential);
    }
    catch (AdalException ex)
    {
        if (ex.ErrorCode == "temporarily_unavailable")
        {
            retry = true;
            retryCount++;
            Thread.Sleep(3000);
        }
    }

} while ((retry == true) && (retryCount < 3));

if (result == null)
    return Request.CreateResponse(HttpStatusCode.InternalServerError, "Could not authenticate against API.");

But when I use the bearer token with with the request from the Web App to the API App I always get a 401 unauthorized response:

StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Date: Wed, 13 Jul 2016 08:43:09 GMT
  Server: Microsoft-IIS/8.0
  WWW-Authenticate: Bearer realm="MY-API-APP-ID-IS-HERE"
  X-Powered-By: ASP.NET
  Content-Length: 58
  Content-Type: text/html
}

This is the code I'm using to make the request that's failing with a 401:

var apiUri = new Uri(ConfigurationManager.AppSettings["ApiUrl"] + "/api/MethodImCalling");
var client = new RestClient(apiUri.GetLeftPart(UriPartial.Authority));
var request = new RestRequest(apiUri, Method.GET);
request.AddHeader("Authorization", "Bearer " + result.AccessToken);
request.AddParameter("something", somevalue);
var response = client.Execute(request);

if (response.StatusCode != HttpStatusCode.OK)
    return Request.CreateResponse(response.StatusCode); // Relay non-successful response

Any ideas what I might be doing wrong or am missing? Thanks in advance!

I already have Logic App in Azure accessing the API App without issue, but I note that the authentication credentials in the logic app json include an "audience" parameter. The code above does not use an "audience" so could this be the missing part of the puzzle, and if so, how do I add it?

Screenshot showing how Web App has been configured to access API App: enter image description here

1
Can you also share details about how you've configured your API for authorization?Philippe Signoret
@PhilippeSignoret - I'm using App Service Authenication = Azure Active Directory "Express" management mode (will add to question also). Is this the detail you're after? Not sure what other detail to provide. Cheers.Gavin
Does the sample code work fine on your local before deploy to Azure? If the access token does not allow you to access your API, I would suggest you use JWT decoded tool to analyze the token, here is the JWT decoded web page: jwt.io.Jambor - MSFT
@Jambor-MSFT - no unfortunately the code isn't working locally or on Azure. Cheers.Gavin
Can you add a screenshot of how you set up you Web App's "Permissions to oter Applications"?Saca

1 Answers

2
votes

The reason you are getting a 401 response is that you've only granted your application Delegated Permissions, yet you are using the client credentials flow which requires Application Permissions.

You can either change your code to use the Authorization Code flow or grant application permissions from your web app to your web API.

To use the Authorization Code flow you'd need to change your code to use AcquireTokenByAuthorizationCodeAsync instead.

You can find more information about these two different approaches here: https://azure.microsoft.com/en-us/documentation/articles/active-directory-authentication-scenarios/#web-application-to-web-api