How to dependency inject Microsoft Graph client in ASP.Net Core 6 Web Api
Asked Answered
G

1

5

I'm trying to setup a web api using ASP.Net Core 6 so that users can hit my end points and then I do some work in Teams using a privileged account. I don't think I am wiring up the DI part correctly because I get the following error when making the request to Teams:

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

Here is how everything is setup:

Program.cs

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

appsettings.json

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "<< domain >>",
    "TenantId": " <<tenant id >>",
    "ClientId": " << client id >>",
    "ClientSecret": " << client secret >>"
  },

  "Graph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "https://graph.microsoft.com/.default"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Teams.cs

namespace GraphApiService.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class Teams : ControllerBase
    {
        private readonly GraphServiceClient _graphServiceClient;

        public Teams(GraphServiceClient graphServiceClient)
        {
            _graphServiceClient = graphServiceClient;
        }

        // GET: api/<Teams>
        [HttpGet]
        public  IEnumerable<string> Get()
        {
            //Throws an error here!
            var teams = _graphServiceClient.Teams[<< team id >>].Request().GetAsync().Result;

            return new string[] { "value1", "value2" };
        }
   }
}

Now if I skip the DI part and just setup the client in the constructor, it works fine.

public Teams()
{
   var scopes = new[] { "https://graph.microsoft.com/.default" };
   var tenantId = " << tenand id >>";
   var clientId = "<< client id >>";
   var clientSecret = "<<client secret>>";

   var options = new TokenCredentialOptions
   {
       AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
   };

   var clientSecretCredential = new ClientSecretCredential(
       tenantId, clientId, clientSecret, options);

  _graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);

}

Any help would be appreciated. Thanks!

Gastrectomy answered 21/3, 2022 at 14:48 Comment(0)
G
7

Well this always happens. Spend two days looking for an answer. Post to a forum, and find the answer a few hours later. I got it to work by using 'WithAppOnly()' like this:

var teams = _graphServiceClient.Teams[teamId].Request().WithAppOnly().GetAsync().Result;

All the examples online use delegated user permissions, so it was hard to find anything on how to to handle app permissions.

Gastrectomy answered 21/3, 2022 at 20:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.