The following forum(s) are migrating to a new home on Microsoft Q&A (Preview): Azure Active Directory!

Ask new questions on Microsoft Q&A (Preview).
Interact with existing posts until December 13, 2019, after which content will be closed to all new and existing posts.

Learn More

 none
HttpClient returning 401 for all calls to AAD secured endpoints RRS feed

  • Question

  • I'm using a System.Net.Http.HttpClient in a windows application to communicate with a secured Web API hosted on an Azure Website authenticated with Azure Active Directory. I set the application up following the AzureADSamples/NativeClient-DotNet application and both the Web API and native client are registered and set up in AAD.

    When I call attempt to call a secured API endpoint (GET, POST, etc.) I get the expected Azure HTML log in form. My credentials are accepted and I add the AuthenticationResult's AccessToken to all future request to the API. However, whenever I make such a call I receive a 401 response. Examination of my HttpClient's headers shows I have the expected Accept header of application/json and Authorization header {Bearer ---token---}. The fact that my log in is accepted and I receive a valid AccessToken suggests to me that AAD authentication is succeeding. I know my account has permissions to the API as I can access the same secure endpoints through a web UI hosted in the same Azure Website using those credentials.

    It looks to me as if the windows application itself doesn't have permissions to access the API. That application has been added to AAD and, after modifying its manifest (super lame BTW) as outlined in this MSDN article I gave it permissions to the web API. Under Azure portal -> AAD application entry for the native windows application -> permissions to other applications:  I have an entry for my web API with delegated permissions set to "Access {my API app}" (and of course the sign-on delegated permissions for my directory).

    I feel like I'm missing something small in some type of configuration but I'm out of ideas where to look.

    Any suggestions you might have will be appreciated.

    Thanks

    Sunday, March 15, 2015 4:51 AM

Answers

  • Here is the ACTUAL answer for this issue.

    The Web API's Startup class employs this code:

    var options = new WindowsAzureActiveDirectoryBearerAuthenticationOptions
    {
    	Audience = ConfigurationManager.AppSettings["ida:ClientID"],
    	Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
    };
    app.UseWindowsAzureActiveDirectoryBearerAuthentication(options);
    

    The ida:ClientID is set in the web.config's appSettings as the Client ID associated with the AAD application for the Web API. I also have an ida:Audience appSetting which is set as the App ID URI associated with the AAD application. The native client is passing a resourceId value that I'd set in the app.config as the App ID URI for the AAD application associated with the Web API. I changed that native client value to be the Client ID for the Web API's AAD application and voila! Note that I could have also changed the Audience property setting of the options to pull the ida:Audience instead except I'm also employing an Angular JS web application which is using ADAL JS and that ppears to only accept Client ID.

    • Marked as answer by Dane Vinson Tuesday, March 31, 2015 11:35 PM
    Tuesday, March 31, 2015 11:35 PM

All replies

  • Hello,

    Thank you for your post. We are researching on the query and would get back to you soon.

    Thank you for your patience.

    Regards,

    Neelesh.

    Sunday, March 15, 2015 3:24 PM
    Moderator
  • More information in the hope someone will spot my issue. Here is the code I'm using in the Windows client application.

    AuthenticationResult authResult = authenticationContext.AcquireToken(resourceUri, clientId, redirectUri);
    var client = new HttpClient();
    client.BaseAddress = "https://mywebapi"
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); }
    var response = await client.GetAsync("controller\method");
    

    I know the resourceUri, clientId and redirectUri are all valid as the authResult returned is valid (i.e. contains a valid AccessToken) but the response is always 401. I know the endpoint https://mywebapi/controller/method is valid and secured with AAD because I can access it through the web UI (hosted in parallel to the Web API) when I'm AAD authenticated there. My Web API's AAD manifest has been edited with the following as outlined in the article I previously linked. 

    "oauth2Permissions": [
    	{
    	  "adminConsentDescription": "Allow the application to access MyWebApi on behalf of the signed-in user.",
    	  "adminConsentDisplayName": "Access MyWebApi",
    	  "id": "{my GUID}",
    	  "isEnabled": true,
    	  "origin": "Application",
    	  "type": "User",
    	  "userConsentDescription": "Allow the application to access MyWebApi on your behalf.",
    	  "userConsentDisplayName": "Access MyWebApi",
    	  "value": "user_impersonation"
    	}
    ],
    

    I've verified that the AAD application entry for the Windows client has been given access to the Web API through the Azure Portal by selecting "Access MyWebApi" in it's delegated permissions.

    What am I missing?

    Wednesday, March 18, 2015 10:53 PM
  • We will need to review fiddler traces and the tenant information to further troubleshoot this, can you please create a support incident to further troubleshoot this so that we can collect this information.
    Thursday, March 19, 2015 2:16 PM
  • Please point me to where I can do that. The only support option I found tells me my current plan doesn't allow for technical support.
    Thursday, March 19, 2015 3:14 PM
  • Yes, you will need a technical support incident for this issue.
    http://azure.microsoft.com/en-us/support/plans/
    Thursday, March 19, 2015 3:16 PM
  • Don't mark this as answered. "Go and pay to open a support ticket" is not an answer. Once it's marked as answered other forum users, who may actually be able to provide some information, will be more likely to not even look.
    Thursday, March 19, 2015 4:03 PM
  • Hello Dane,

    Apologies for the same, however this is beyond the MSDN Forum Support Scope as we need detailed information for troubleshooting the issue and a Technical Ticket needs to be created for the same.

    Regards,

    Neelesh.

    Monday, March 23, 2015 9:53 AM
    Moderator
  • Here is the ACTUAL answer for this issue.

    The Web API's Startup class employs this code:

    var options = new WindowsAzureActiveDirectoryBearerAuthenticationOptions
    {
    	Audience = ConfigurationManager.AppSettings["ida:ClientID"],
    	Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
    };
    app.UseWindowsAzureActiveDirectoryBearerAuthentication(options);
    

    The ida:ClientID is set in the web.config's appSettings as the Client ID associated with the AAD application for the Web API. I also have an ida:Audience appSetting which is set as the App ID URI associated with the AAD application. The native client is passing a resourceId value that I'd set in the app.config as the App ID URI for the AAD application associated with the Web API. I changed that native client value to be the Client ID for the Web API's AAD application and voila! Note that I could have also changed the Audience property setting of the options to pull the ida:Audience instead except I'm also employing an Angular JS web application which is using ADAL JS and that ppears to only accept Client ID.

    • Marked as answer by Dane Vinson Tuesday, March 31, 2015 11:35 PM
    Tuesday, March 31, 2015 11:35 PM
  • I had the same problem - 401 Unauthorized when trying to access a WebAPI through the Azure AD Authentication.

    In my case the problem was the end slash mismatch between the ida:Audience value and the actual App ID URI in the Azure AD Web API application configuration. I've gone through all the setting for couple of times, failing to notice the missing end slash in my web.config, so once more: check again if your keys exactly match each other.

    Thanks to Dane for the hints above, very helpful, especially when you've passed through a bunch of now obsolete tutorials and how-tos.



    .. thinks sometimes

    Thursday, September 17, 2015 11:25 AM