22

I'm trying create a C# console application to connect to graph API and get a list of users from AzureAD from a tenant. I have registered the app and the admin has given me the following

  • Tenant Name and Tenant ID
  • Client ID (also sometimes called App Id)
  • Client Secret

Using the sdk the C# code I need to use looks like this (https://learn.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=cs):

GraphServiceClient graphClient = new GraphServiceClient( authProvider );

var users = await graphClient.Users
    .Request()
    .GetAsync();

However, the console application will run as a batch process so there will be no user interaction at all. So in order to provide the authProvider I followed this article on MS docs site: https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS

And I think for my purpose I need to go for the "Client Credential OAuth flow". The code which is shown on that URL. But here it is too.

IConfidentialClientApplication clientApplication = ClientCredentialProvider.CreateClientApplication(clientId, clientCredential);
ClientCredentialProvider authProvider = new ClientCredentialProvider(clientApplication);

The trouble is that Visual Studio does not recognise ClientCredentialProvider class. I'm not sure which assembly to import. I'm using the following usings in the top.

using Microsoft.Identity.Client;
using Microsoft.IdentityModel.Clients;
using Microsoft.IdentityModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

I'm not very experienced with GitHub repos and I'm using Visual Studio 2015. I would be interested in sample code; I have looked but cannot find any. MS have some lectures but they use another type of auth Provider which is authenticating interactively which is not what I'm looking for. I want obtain the token using the TenantId/ClientId and Client Secret.

halfer
  • 19,824
  • 17
  • 99
  • 186
gtrivedi
  • 435
  • 1
  • 7
  • 18

3 Answers3

52

ClientCredentialProvider is part of the Microsoft.Graph.Auth package. You can read more about this package at https://github.com/microsoftgraph/msgraph-sdk-dotnet-auth

Note that this package is currently (as of 2019-05-15) in preview, so you may want to wait before using this in a production application.

Alternatively, the following example uses the Microsoft Authentication Library for .NET (MSAL) directly to set up the Microsoft Graph SDK using app-only authentication:

// The Azure AD tenant ID or a verified domain (e.g. contoso.onmicrosoft.com) 
var tenantId = "{tenant-id-or-domain-name}";

// The client ID of the app registered in Azure AD
var clientId = "{client-id}";

// *Never* include client secrets in source code!
var clientSecret = await GetClientSecretFromKeyVault(); // Or some other secure place.

// The app registration should be configured to require access to permissions
// sufficient for the Microsoft Graph API calls the app will be making, and
// those permissions should be granted by a tenant administrator.
var scopes = new string[] { "https://graph.microsoft.com/.default" };

// Configure the MSAL client as a confidential client
var confidentialClient = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithAuthority($"https://login.microsoftonline.com/$tenantId/v2.0")
    .WithClientSecret(clientSecret)
    .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. 
GraphServiceClient graphServiceClient =
    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);
        })
    );

// Make a Microsoft Graph API query
var users = await graphServiceClient.Users.Request().GetAsync();

(Note that this example uses the latest version of the Microsoft.Identity.Client package. Earlier versions (before version 3) did not include ConfidentialClientApplicationBuilder.)

Philippe Signoret
  • 13,299
  • 1
  • 40
  • 58
  • Thanks for the response Philippe. The code compiles fine but doesn't do much. I added a foreach after the last line to iterate through the users but it doesn't even go to the foreach line. I must be doing something wrong? – gtrivedi May 16 '19 at 09:09
  • @gtrivedi We'll need some more concrete details in order to be able to help. Have you tried setting a breakpoint and stepping through what's happening? – Philippe Signoret May 16 '19 at 11:29
  • Yes I put a break point on the last line. var users... Immediately after that I have a foreach(var item in users){....} and the compiler exists and doesn't even go to the foreach loop. – gtrivedi May 20 '19 at 14:05
  • 1
    I have same behavior: got token succesfully in DelegateAuthenticationProvider, but then infinity call of users request. But without MSAL library works for me. This works for example https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2 Maybe for some on it would be a solution, but I want to use library – Andrey Kucher Dec 03 '19 at 13:04
  • After some fiddlering I have found a problem: graphClient.Me returns 404 (maybe permissions problem). So graphServiceClient.Users is working good. Is it possible to get error in code instead of fiddler? – Andrey Kucher Dec 03 '19 at 14:34
  • 5
    Worth to mention that **Microsot.Graph.Auth** library is not going to leave prerelease stage at all. [GitHub](https://github.com/microsoftgraph/microsoft-graph-docs/issues/9137) – krypru Jun 21 '21 at 09:02
  • Hi @PhilippeSignoret. Do you happen to have any idea about this issue? https://stackoverflow.com/questions/69329470/why-is-my-graphserviceclient-reauthenticating-at-every-api-call – Rafa Ayadi Sep 25 '21 at 21:30
2

As mentioned above - at the time of writinf Sept 2021, the package: Microsoft.Graph.Auth is deprecated. This means ClientCredentialProvider is no longer available. https://www.nuget.org/packages/Microsoft.Graph.Auth/

The alternative is to use the solution propsed by Philippe above.

PaulGrant
  • 358
  • 3
  • 9
  • 2
    This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/29774748) – Paulo Sep 10 '21 at 10:21
-3

If you wanna cycle trough the users, replace the var users with the following code:

IGraphServiceUsersCollectionPage users = graphServiceClient.Users.Request().GetAsync().Result;
foreach (User user in users)
{
Console.WriteLine("Found user: " + user.Id);
}
p-a-o-l-o
  • 9,807
  • 2
  • 22
  • 35
Marek Kyzivát
  • 323
  • 2
  • 16