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
- Web API
- Token cache serialization
- 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);
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?
Is this a new or an existing app?
C. This is a new app
Repro
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: