2

I'm developping a tool (Windows Forms) to automate certain processes. I need to read the members of specific AD group and create an event in each members calendar. For this I use the GraphServiceClient in a C# application.

  1. I've added an "App registration" in the Azure Portal: Jansen Automation
  2. I've added all permissions needed AND granted admin consent

enter image description here

  1. I've created a ClientSecret a copied the value of it to my code

enter image description here

Next I want to read all groups from AD, using the example code from https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#tabpanel_2_CS:

    private GraphServiceClient GetClient()
    {
        try
        {
            var scopes = new[] { "https://graph.microsoft.com/.default" };

            // Multi-tenant apps can use "common",
            // single-tenant apps must use the tenant ID from the Azure portal
            var tenantId = _options.TenantId;

            // Values from app registration
            var clientId = _options.ClientId;
            var clientSecret = _options.ClientSecret;

            // using Azure.Identity;
            var options = new TokenCredentialOptions
            {
                AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
            };

            // https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
            var clientSecretCredential = new ClientSecretCredential(
                tenantId, clientId, clientSecret, options);

            var graphClient = new GraphServiceClient(clientSecretCredential, scopes);

            return graphClient;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, ex.Message);
            throw;
        }
    }

    public async Task<List<string>> GetAllGroups()
    {
        try
        {
            var client = GetClient();
            var groups = await client.Groups
                               .Request()
                               .Header("ConsistencyLevel", "eventual")
                               .GetAsync();

            return groups?.Select(g => g.DisplayName).ToList();
        }
        catch (Exception ex)
        {
            throw;
        }
    }

The result is an exception:

enter image description here

What am I missing here?

Berrepoot
  • 141
  • 10

1 Answers1

4

I've figured it out, I've granted delegated permissions instead of application permissions. I've changed it to application and my code now looks like this:

var scopes = new string[] { "https://graph.microsoft.com/.default" };
var tenantId = clientConfig.TenantId;

// Configure the MSAL client as a confidential client
var confidentialClient = ConfidentialClientApplicationBuilder
                .Create(clientConfig.ClientId)                
 .WithAuthority($"https://login.microsoftonline.com/{tenantId}/v2.0")
                .WithClientSecret(clientConfig.Secret)
                .Build();

 // Build the Microsoft Graph client. As the authentication provider, set an async lambda
// which uses the MSAL client to obtain an app-only access token to Microsoft Graph,
// and inserts this access token in the Authorization header of each API request. 

 return new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) => {

   // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
     var authResult = await confidentialClient
              .AcquireTokenForClient(scopes)
              .ExecuteAsync();

   // Add the access token in the Authorization header of the API request.
     requestMessage.Headers.Authorization =
                        new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
                })
                );
            });
Berrepoot
  • 141
  • 10
  • Worked perfectly for me after banging my head against the Microsoft documentation for an afternoon. Thanks much! – barvobot Oct 13 '22 at 21:11
  • After days of searching, this is the first functional code. Thanks. – bmi Jan 12 '23 at 15:21