2

I am trying to make a simple call with the Microsoft Graph API SDK using the Microsoft.Identity.Web library from within a web api project.

The user is already logged in and is calling protected controllers from a SPA and everything is working fine - but now, these controlles should make a call to the Graph API and I don't get it up and running...

I found a perfect sample that shows how easy it is with a wep app here. And it is really as easy as this:

.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
   .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
   .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
   .AddInMemoryTokenCaches();

As I want to use this functionality within a web api project, I created a new project of that type, copied the code and got:

MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.

and

MicrosoftIdentityWebChallengeUserException: IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent.

Then I thought, ok, as this is now api related, I will change the code from

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                 .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
                 .EnableTokenAcquisitionToCallDownstreamApi(new string[] { "user.read" })
                 .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
                 .AddInMemoryTokenCaches();

to

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                 .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
                 .EnableTokenAcquisitionToCallDownstreamApi()
                 .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
                 .AddInMemoryTokenCaches();

but I get the same error.

I navigated to https://aka.ms/ms-id-web/ca_incremental-consent as mentioned in the exception message and found Handling incremental consent or conditional access in web APIs:

public async Task<string> CallGraphApiOnBehalfOfUser()
{
 string[] scopes = { "user.read" };

 // we use MSAL.NET to get a token to call the API On Behalf Of the current user
 try
 {
  string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
  dynamic me = await CallGraphApiOnBehalfOfUser(accessToken);
  return me.UserPrincipalName;
 }
 catch (MicrosoftIdentityWebChallengeUserException ex)
 {
  await _tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeaderAsync(scopes, ex.MsalUiRequiredException);
  return string.Empty;
 }
 catch (MsalUiRequiredException ex)
 {
  await _tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeaderAsync(scopes, ex);
  return string.Empty;
 }
}

I tried this and get the same error:

IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent.

When later finding the sample Web API calling downstream web API, I thought now everything gets easy but although, a WebAPI is calling Microsoft Graph, they are using a Windows application to sign in the user first.

On stackoverflow, I found How to access Graph API from Web API in SPA application but unfortunately, this question is hopefully out-dated.

Has anyone an idea how to get the sample code for the web app up and running in a web api only project? (No windows application involved)

I am using

Microsoft.Graph 3.21.0

Microsoft.Identity.Web version 1.4.0

timtos
  • 2,225
  • 2
  • 27
  • 39
  • Whether using a Windows application to sign in the user or not doesn't effect the subsequent verification process. You can learn more details from [OAuth 2.0 On-Behalf-Of flow](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow). You should be able to get an access token from SPA authentication to access web API. Use this access token to request the new access token which is for Microsoft Graph. So what you need to focus on is the code how to get the second access token which is for Microsoft Graph. – Allen Wu Dec 14 '20 at 04:25
  • https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/2.%20Web%20API%20now%20calls%20Microsoft%20Graph this sample should be what you want. – Allen Wu Dec 14 '20 at 04:26
  • So there is no "easy" way via AddMicrosoftIdentityWebApi. I saw your sample before but the use case is a little different. I am now using the ConfidentialClientApplicationBuilder and for a single tenant scenario it is working but multi tenant is still making problems. But that is perhaps a topic for another question. Thank you @AllenWu – timtos Dec 16 '20 at 09:50
  • For multi-tenant, you should specify the tenant id as `common`. See https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/blob/master/2.%20Web%20API%20now%20calls%20Microsoft%20Graph/TodoListService/appsettings.json. `"TenantId": "common"` – Allen Wu Dec 17 '20 at 04:03

2 Answers2

2

I think that instead of using AddMicrosoftGraph, you need to use AddMicrosoftGraphAppOnly.

So in your example this will be like:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddMicrosoftGraphAppOnly(authenticationProvider => new GraphServiceClient(authenticationProvider))
    .AddInMemoryTokenCaches();
Stef Heyenrath
  • 9,335
  • 12
  • 66
  • 121
0

2. Web API now calls Microsoft Graph is that one that you're looking for. The fact that the client is a windows application is not relevant. Try it and let me know how it goes.

AlfredoRevilla-MSFT
  • 3,171
  • 1
  • 12
  • 18
  • Thanks Alfredo, that's the link Allen mentioned as well. As I wrote above in the comments, the use case is different, but yes, something like this is working. Unfortunately it seems, that one has to handle the token cache serialization oneself and the the refreshing of the tokens as well. That's why I was hoping that there is a way using AddMicrosoftIdentityWebApi or AddMicrosoftIdentityWebApp. – timtos Dec 17 '20 at 11:53