Why doesn’t the “https://login.microsoftonline.com/common” AAD endpoint work, while the “https://login.microsoftonline.com/[tenant ID]” does?

Franco Scarpa 21 Reputation points
2021-03-08T13:39:53.427+00:00

I’m developing a UWP application that calls an API. The API is made of an Azure Function triggered by HTTP requests. I want the Azure Function to be secured through Azure Active Directory. To do so, I created two app registrations in AAD, one for the UWP and one for the API. Both support accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g., Skype, Xbox). The API app registration provides scope, and the UWP app registration uses that scope. The code I use on my UWP is:

var HttpClient _httpClient = new HttpClient();  
const string clientId      = "[UWP app registration’s client ID]";  
const string authority     = "https://login.microsoftonline.com/[Tenant ID of the UWP app registration]";  
string[] scopes            = { "api://[API app registration’s client ID]/[scope]" };  
  
var app = PublicClientApplicationBuilder  
             .Create(clientId)  
             .WithAuthority(authority)  
             .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")  
             .Build();  
  
AuthenticationResult result;  
var accounts = await app.GetAccountsAsync();  
  
try {  
   result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();  
}  
catch (MsalUiRequiredException) {  
   try {  
      result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();  
   }  
   catch (Exception exception) {  
      Console.WriteLine(exception);  
      throw;  
   }  
}  
  
if (result == null) return;  
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);  
 var response = _httpClient.GetAsync("[API URL]").Result;  

This code works, but if I replace the authority with https://login.microsoftonline.com/common (as specified here), being my app registrations multi-tenant, I get a 401 response when calling the API _httpClient.GetAsync("[API URL]").Result. The docs say the code must be updated somehow when using the /common endpoint, but I don’t understand how I should edit it. Can anyone help me, please?

Microsoft Security | Microsoft Entra | Microsoft Entra ID
Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. cheong00 3,486 Reputation points Volunteer Moderator
    2021-03-09T03:03:32.533+00:00

    Not written anything for AAD, but from the documentation, it says that when you specify "/common" endpoint instead of tenant, the issuer in returned token will contain the templated URL instead of GUID value of issuer, so you cannot just use the "issuer in metadata" (as in: https://login.microsoftonline.com/contoso.onmicrosoft.com/.well-known/openid-configuration ) to match "issuer value in token" for validation.

    Therefore you should disable issuer validation for it to work.

    Instead they should use "issuer value" or the "tid claim value" in the token to match against list of valid subscribers (maybe here's the point of confusion? I would have used a test account from each of the tenant in interest to login and capture the returned token, and in turn use the tokens captured to build the list of expected values for each tenants.

    Maybe you should check the example on /common endpoint and see if it can clear things up a bit. This section on OnTokenValidated event handling shows how to do validation with .tid field mentioned before. These example does not use HttpClient and use OpenID Connect ASP.NET Core middleware library instead.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.