Search code examples
azureasp.net-coremicrosoft-identity-platformmicrosoft-identity-webgrpc-c#

Problem calling Microsoft Graph from ASP.NET Grpc service


I have two applications -

  • public client application (.NET Core console app), in which user gets Microsoft identity access token
  • web API, which tries to call Microsoft Graph on-behalf-of user, using that access token

When I call Microsoft Graph from web API, I get a MicrosoftIdentityWebChallengeUserException, which inner exception states: "The user or administrator has not consented to use the application with ID <...> named <...>. Send an interactive authorization request for this user and resource."

I've tried:

  • to pre-authorize client application in service application using Expose an API tab in Azure Portal
  • to add client application ID in knownClientApplications array in Manifest tab
  • to include the scopes, needed for Microsoft Graph (e.g. "User.Read"), in the access token, obtained by the user

but it seems that this does not work and I still get the same exception.

The question is - can I somehow avoid this exceptional situation by getting all needed permissions in a user access token, before calling the GRPC service, or if not, that how do I need to handle this exception to propagate it back to the user.


Solution

  • Full details here. Keep following the Next Steps.

    Basically, you'll need to:

    Include the Microsoft.Identity.Web and Microsoft.Identity.Web.MicrosoftGraph NuGet packages in your API project.

    Set up a Client Secret or a Certificate in the Azure App Registration. Include that in your appsettings.json file:

    "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "Domain": "{YOUR-DOMAIN-NAME-FROM-APP-REGISTRATION}",
        "TenantId": "{YOUR-TENANT-ID-FROM-APP-REGISTRATION}",
        "ClientId": "{YOUR-CLIENT-ID-FROM-APP-REGISTRATION}",
        "Scopes": "{YOUR-API-ACCESS-SCOPE-FROM-APP-REGISTRATION}",
        "CallbackPath": "/signin-oidc",
        "ClientSecret": "{YOUR-CLIENT-SECRET-FROM-APP-REGISTRATION}"
      }
    

    Include the following section in your appsettings.json file:

    "Graph": {
        "BaseUrl": "https://graph.microsoft.com/v1.0",
        "Scopes": "User.Read"
      }
    

    Include the following code in your Project.cs file or Startup.cs file (depending on what version of .Net you're using):

    Startup.cs:

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

    Project.cs:

    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi()
                   .AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
                .AddInMemoryTokenCaches();
    

    From there, you just need to inject the GraphServiceClient into your controller or page constructor. The link above provides code for implementation in an ASP.NET API. I'm using this method in a Blazor Webassembly hosted app, so my implementation needs varied slightly from the instructions, but it's running/working as it should.