Graph SDK GraphServiceClient
I used this page to create a template for connecting to the MS Graph API in C#. It creates a console application with everything you need to get started.
These notes are my analysis of how the Graph API connection used in this template works. Feel free to correct any erroneous assumptions I made.
This application uses the Graph SDK to handle the authentication and requests for the Graph API.
using Microsoft.Graph;
Device Code Authentication
The chosen authentication method is called Device Code credentials [other available methods]. This authentication method assumes that the device running the code, will not have access to a browser. It provides a link and a unique code so the user can use a different device to authenticate themselves and grant permissions.
private static DeviceCodeCredential? _deviceCodeCredential;
GraphServiceClient Object
You will be using the GraphServiceClient to handle authentication, calls, and responses from the Graph API. I could not find the page that has the definition for this object but the example creates one by passing a TokenCredential and a list of strings (IEnumerable) of the desired scopes. A baseUrl string is an optional parameter seen in the Visual Studio hover message. Other items that can be used, according to the overloads, are: IRequestAdapter, HttpClient, and IAuthenticationProvider.
private static GraphServiceClient? _userClient;
/*
GraphServiceClient(
TokenCredential tokenCredential,
[IEnumerable<string> scopes = null,
[string baseUrl = null]
)
*/
Authentication Token
The token credential is used to acquire an access token, while scopes tell it what you what to access and at what level.
A token represents the authorization to access the information that the API contains. In this case, the information that the user has stored in the different Microsoft services.
Before passing a Token Credential to the Graph Service Client you will most likely need to set some options for it. Both the credentials and options have predefined classes you can use.
Device Code Credential Options
In the case of the device code flow used in this template, we can use DeviceCodeCredentialsOptions class for setting the desired options for this application. We will need to set a ClientID, TenantID, and DeviceCodeCallback.
The ClientID is a unique id that identifies your application, the TenantID is for identifying the resource you want to access (organizations can have their own tenant id which identifies that organizations data), and the DeviceCodeCallback is a callback function that is used to display to the user: the code and URL for logging in and granting the necessary permissions for the application.
var options = new DeviceCodeCredentialOptions {
ClientId = settings.ClientId,
TenantId = settings.TenantId,
DeviceCodeCallback = deviceCodePrompt,
};
JSON Configuration File
This template uses a custom settings class which holds the ClientId, TenantId, and GraphUserScopes. These values are obtained by reading the appsettings JSON file (where the values are store for easy modification and confidentiality of the data). This data structure is passed to InitializeGraphForUserAuth along with the a Func. These values are used to setup the Graph Service Client object for connecting to the API.
public static void InitializeGraphForUserAuth(Settings settings, Func<DeviceCodeInfo, CancellationToken, Task> deviceCodePrompt)
Func Encapsulation of Delegate
The Func encapsulation is used to create a delegate (a variable that holds a reference to a function), it takes one or more parameters followed by the output type. In this case we create a function with the parameters DeviceCodeInfo and CancellationToken, and an output of type Task.
DeviceCodeCallback Parameters
The DeviceCodeInfo struct holds the information you need for the user to login using the device code flow. The proprieties it contains are ClientId, DeviceCode, ExpiresOn, Message, Scopes, UserCode, and VerificationUri.
The CancellationToken property is used to cancel the invoked action, if it is no longer needed or any other reason.
The Task class represents an asynchronous operation (a promise).
Creating the Callback Function
The template passes a Lambda expression (anonymous function) to InitializeGraphForUserAuth as the deviceCodePrompt:
(info, cancel) => {
// Display the device code message to the user.
// This tells them where to go to sign in
// and provides the code to use.
Console.WriteLine(info.Message);
return Task.FromResult(0);
}
As defined it contains two parameters and returns a Task. The info parameter, which represents the DeviceCodeInfo struct, is used to display the prefabricated message on the command line. The message contains the URL and code for authentication. Then it returns a task; the FromResult method used is for creating a successful completion of the task, hence assigning the result value to 0.
Initializing Graph Service Client
With these parameters we now have the necessary data to initialize the Graph Service Client. First we set the options we need for the device code credential:
var options = new DeviceCodeCredentialOptions {
ClientId = settings.ClientId,
TenantId = settings.TenantId,
DeviceCodeCallback = deviceCodePrompt,
};
Then a DeviceCodeCredential object is created with the previous options
_deviceCodeCredential = new DeviceCodeCredential(options);
Next we can create the client
_userClient = new GraphServiceClient(deviceCodeCredential, settings.GraphUserScopes);
The client will use the credential for asking the API to create a token for user data at the specified scopes. Once the client is created, it can be used to make calls to the Graph API. If a call is successful, it will return the requested data.
Let me know if anything is unclear, or if you would explain it differently.
Subscribe to my newsletter
Read articles from Dianne De Jesus directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by