This post is a part of The Second Annual C# Advent.
Microsoft Graph is the unified API for any developers working with data inside Office 365, Azure Active Directory (Azure AD), Windows 10, and more. In this post we’ll cover a quick introduction and share resources from 30 Days of Microsoft Graph blog series to show how to authenticate and to make calls against Microsoft Graph with C# and .Net Core (v2.1 as of the time of writing.) Each of the referenced articles aims to take 5-15 mins to get you up to speed as quickly as possible while also providing hands-on exercises. If you’d like to skip the background reading and start from scratch building a .Net Core console application that calls Microsoft Graph read through the README for the base-console-app within dotnetcore-console-sample.
<Update 2019-10-07>Thanks to reader John Guilbert for pointing out that the sample code using MSAL .Net 2.x has deprecated certain APIs. I’ve updated the sample code to reflect MSAL .Net 4.x.</Update>
Microsoft Graph overview
Microsoft Graph offers developers (and IT pros / admins) the ability to access data and insights in a number of services within Microsoft 365 services. This includes:
- Azure AD
- Office 365 services
- SharePoint
- OneDrive
- Outlook/Exchange
- Microsoft Teams
- OneNote
- Planner
- Excel
- Enterprise Mobility and Security services
- Identity Manager
- Intune
- Advanced Threat Analytics
- Advanced Threat Protection
- Windows 10 services
- Activities
- Devices
- Education
By providing a unified endpoint for accessing all of these services Microsoft Graph removes a number of barriers including:
- Discovering the service-specific endpoint URL
- Authenticating to each endpoint separately
- Managing different permission models
- Working with incompatible data formats
- …and more
All requests made to Microsoft Graph are sent as REST calls to https://graph.microsoft.com and leverage a common authentication model based on Azure AD and OAuth permissions along with a consent framework for users or admins. The quickest way to see Microsoft Graph requests in action is to navigate to the Microsoft Graph explorer (https://aka.ms/ge, ge = Graph Explorer.) For more information on using Graph Explorer please read Day 3 – Graph Explorer from the 30 Days of Microsoft Graph series. Additionally you can make requests against Microsoft Graph using API development tools such as Postman. Please read Day 13 – Postman to make Microsoft Graph requests for more information on using PostMan with Microsoft Graph.
Getting started sample
Seeing requests and their responses in a browser or tool is useful, but making requests in code or scripts is the more common scenario for usage. In the examples below we will cover C# and .Net Core as .Net Core is available cross-platform, can be built in Visual Studio Code (also cross-platform), and offers many hosting options (console app, web app, serverless functions, and more.)
Authentication
All requests to Microsoft Graph require an authenticated context, either delegated or app-only. Delegated is a union of the logged-in user’s context along with the application’s context. App-only (as the name implies) is only the application’s context without any user involvement. Please read Day 8 – Authentication roadmap and access tokens and Day 9 – Azure AD applications on V2 endpoint for more information about creating an Azure AD application and getting an authenticated context. On a similar note, you are highly encouraged to leverage Microsoft Authentication Library (MSAL) for creating your authentication context as this is the forward-focused version as opposed to the older Active Directory Authentication Library (ADAL).
Microsoft Graph SDK
While it is entirely possible to call the Microsoft Graph with an HttpClient (or similar) object, the Azure AD Identity and Microsoft Graph product groups recommend leveraging the Microsoft Graph SDK (Microsoft.Graph on Nuget.) This SDK provides a number of benefits including:
- Strongly typed entities and Microsoft Graph responses
- Fluent API syntax
- …and more
In future releases Microsoft Graph SDK will also provide abstractions for authentication prerequisites, automatic handling of retry logic or error handling, and more.
Sample solution
As mentioned at the beginning of this post if you’d like to build a working application from scratch (or clone the repo and configure the necessary settings) you can find the base-console-app within dotnetcore-console-sample. Extracting the bare essential lines of code from this sample results in the following for authenticating to Microsoft Graph.
Note: If you do not see the below Gist please refer to code at this location: CS-Graph_Prepare_GraphServiceClient.cs
https://gist.github.com/BrianTJackett/3c629bca714325440cffce73e6b3bf56.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var clientId = "<AzureADAppClientId>"; | |
var clientSecret = "<AzureADAppClientSecret>"; | |
var redirectUri = "<AzureADAppRedirectUri>"; | |
var authority = "https://login.microsoftonline.com/<AzureADAppTenantId>/v2.0"; | |
var cca = ConfidentialClientApplicationBuilder.Create(clientId) | |
.WithAuthority(authority) | |
.WithRedirectUri(redirectUri) | |
.WithClientSecret(clientSecret) | |
.Build(); | |
// use the default permissions assigned from within the Azure AD app registration portal | |
List<string> scopes = new List<string>(); | |
scopes.Add("https://graph.microsoft.com/.default"); | |
var authenticationProvider = new MsalAuthenticationProvider(cca, scopes.ToArray()); | |
GraphServiceClient graphClient = new GraphServiceClient(authenticationProvider); |
The following class implements the IAuthenticationProvider interface used for retrieving and then adding an Azure AD access token to subsequent requests to Microsoft Graph. An out of the box implementation of this class will be provided at a later date within the Graph SDK.
Note: If you do not see the below Gist please refer to code at this location: CS-Graph_Class_MsalAuthenticationProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MsalAuthenticationProvider : IAuthenticationProvider | |
{ | |
private IConfidentialClientApplication _clientApplication; | |
private string[] _scopes; | |
public MsalAuthenticationProvider(IConfidentialClientApplication clientApplication, string[] scopes) { | |
_clientApplication = clientApplication; | |
_scopes = scopes; | |
} | |
public async Task AuthenticateRequestAsync(HttpRequestMessage request) | |
{ | |
var token = await GetTokenAsync(); | |
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token); | |
} | |
public async Task<string> GetTokenAsync() | |
{ | |
AuthenticationResult authResult = null; | |
authResult = await _clientApplication.AcquireTokenForClient(_scopes).ExecuteAsync(); | |
return authResult.AccessToken; | |
} | |
} |
https://gist.github.com/BrianTJackett/c69c1991eac2b3f5a76996d17223299a.js
Finally make a sample request to get a list of users within the Azure AD domain by calling Microsoft Graph.
Note: If you do not see the below Gist please refer to code at this location: CS-Graph_Request_Users_GraphServiceClient.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var graphResult = graphClient.Users.Request().GetAsync().Result; | |
Console.WriteLine(graphResult[0].DisplayName); |
Conclusion
In this blog post we covered a quick introduction of Microsoft Graph and linked to additional resource within the 30 Days of Microsoft Graph blog series for additional background reading. We also covered a barebones implementation of calling Microsoft Graph in a C# .Net Core console application. Full instructions can be found on the base-console-app within dotnetcore-console-sample. Thank you for reading along and please open an issue on GitHub repo if you run into any issues with the sample project. Enjoy the rest of The Second Annual C# Advent.
-Frog Out
[…] by /u/mgroves [link] […]
LikeLike
[…] Introduction to Calling Microsoft Graph from a C# .Net Core Application […]
LikeLike
[…] [2] Blog post by Brian Jackett: https://briantjackett.com/2018/12/13/introduction-to-calling-microsoft-graph-from-a-c-net-core-appli… […]
LikeLike
“AcquireTokenForClientAsync” is now deprecated and you are supposed to be using “AcquireTokenForClient” instead:
authResult = await _clientApplication.AcquireTokenForClient(_scopes).ExecuteAsync();
LikeLike
John, thanks for pointing that out. You are correct that the current version of MSAL .Net (4.2.X at time of writing) requires a different syntax for acquiring a token compared to when this post was first published (2.X). I’ll update post to reflect that but in the meantime see this article I wrote on the Microsoft Graph blog for the syntax used in MSAL .Net 4.X: https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-upgrading-to-msal-net-v4/
LikeLike
[…] on my “Introduction to Calling Microsoft Graph from a C# .Net Core Application” post from the 2018 C# Advent event, this year we’ll take what we learned and adapt […]
LikeLike
Hey Thanks for your post, I know it was a long time ago but it’s just getting more popular, so I tried it as well and it works for “/users” but not for “/me”
in my case I have just User.Read permission and it is enough for my app but I don’t know how to call on behalf of that user and 3 day on internet were not helpful, any ideas on that?
LikeLike
The sample provided is using application permissions which has no user context (app-only). To use the /me endpoint you will need to use delegated permissions (app+user). See this sample https://github.com/microsoftgraph/dotnetcore-console-sample/tree/main/day20-devicecode for device code auth flow or look into authorization code auth flow.
LikeLike
If I have use for /me then I have use Device code. But I dont want user or anyone should enter the credentials or pop should come for entering the credentials. Is there a way to get the access token directly in Delegated permissions?
LikeLike
Unfortunately not in a way that is recommended.
LikeLike
Hi Brian,
This is presumably a pretty dumb question, but I’ll try my luck anyways. I have an asp.net webforms application in which I am trying to do a Graph API call. I got the code build with success (first tried your console app), but when the http request gets executed, the page stays loading for ages, no timeout or anything. I think I am missing someting, most likely it has something to do with the async way of working, or maybe webforms isn’t even up to par to perform these kinds of actions. Any tips?
Great article and sample code by the way!
Kr,
Anthony.
LikeLike
I would start here with our ASP.Net Core (or Framework for back compat) samples and tutorials. Yes there will be some differences compared to console app.
https://developer.microsoft.com/en-us/graph/get-started/dotnet-core
LikeLike
[…] post is a part of Festive Tech Calendar 2022 and a follow-up to Introduction to Calling Microsoft Graph from a C# .Net Core Application from […]
LikeLike