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?

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,094 questions
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
19,086 questions
0 comments No comments
{count} votes

Accepted answer
  1. Cheong00 3,466 Reputation points
    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