Skip to content

[Bug] Unable to call AAD Protected Azure Functions from ASP.Net Application #995

Description

@snapfisher

Which version of Microsoft Identity Web are you using?
Note that to get help, you need to run the latest version.
1.6

Where is the issue?

  • Web app
    • Sign-in users
    • Sign-in users and call web APIs
  • Web API
    • Protected web APIs (validating tokens)
    • Protected web APIs (validating scopes)
    • [x ] Protected web APIs call downstream web APIs
  • Token cache serialization
    • In-memory caches
    • Session caches
    • Distributed caches
  • Other (please describe)

Is this a new or an existing app?

C. This is a new app
Repro

var scope = _configuration["CallApi:ScopeForAccessToken"];
var accessToken = await _tokenAcquisition.GetAccessTokenForAppAsync(scope);

var client2 = _clientFactory.CreateClient();
client2.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client2.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client2.GetStringAsync(url);

Given this configuration

"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "xxxx.onmicrosoft.com",
"TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"CallbackPath": "/.auth/login/aad/callback",
"ClientSecret": "x"
},
"CallApi": {
"ScopeForAccessToken": "http://xxxxxxx/.default",
"ApiBaseAddress": "https://as-xxxxxxx.azurewebsites.net/api/HttpsDemo?code=xxxxxx==",
"Resource": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},

Expected behavior
This should work, and I should be able to access the API. The function app is protected with AAD. I can log into the function app in postman my signing in, so I know that works.

Actual behavior
I receive a 401 unauthorized. However, I can get it to work in postman and in the app. I can manually copy the bearer token from postman into the app and it works.

I also tried user.read, user.read.all, and the specific scope that the client SP is given permission on from the API principal. All combinations return a 401

I can also get it to work with this:

                var tenantId = _configuration["AzureAd:TenantId"];
                var clientId = _configuration["AzureAd:ClientId"];
                var clientSecret = _configuration["AzureAd:ClientSecret"];
                var resource = _configuration["CallApi:Resource"];

                HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, $"https://login.microsoftonline.com/{tenantId}/oauth2/token");
                req.Headers.Add("Accept", "*/*");
                req.Content = new StringContent(string.Empty, Encoding.UTF8, "application/x-www-form-urlencoded");

                // This is the important part:
                req.Content = new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "grant_type", "client_credentials" },
                    { "client_id", $"{clientId}" },
                    { "client_secret", $"{clientSecret}" },
                    { "resource", $"{resource}" }
                });

                HttpResponseMessage resp = await client.SendAsync(req);
                string body = await resp.Content.ReadAsStringAsync();
                JObject tok = JObject.Parse(body);

                var client2 = _clientFactory.CreateClient();


                client2.BaseAddress = new Uri(_configuration["CallApi:ApiBaseAddress"]);
                client2.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client2.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tok["access_token"].Value<string>());
                var response = await client2.GetStringAsync(url);

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions