Documentation Index Fetch the complete documentation index at: https://mintlify.com/microsoftgraph/msgraph-sdk-dotnet/llms.txt
Use this file to discover all available pages before exploring further.
This quick start guide will walk you through creating a complete Microsoft Graph .NET application from scratch. In just a few minutes, you’ll register an app, authenticate, and make your first API call.
This guide uses client credentials authentication for simplicity. For production applications with user interaction, see the authentication guide for other authentication flows.
What You’ll Build
By the end of this guide, you’ll have a working console application that:
Authenticates to Microsoft Graph using client credentials
Creates a GraphServiceClient instance
Retrieves user information from your Azure AD tenant
Handles errors gracefully
Register Your Application in Azure Portal
Before you can call Microsoft Graph, you need to register your application in Azure Active Directory. Navigate to Azure Portal
Go to the Microsoft Application Registration Portal
Sign in with your Microsoft 365 account (work or school account)
Create a New Registration
Click New registration
Enter an application name (e.g., “My Graph App”)
Select Accounts in this organizational directory only for the supported account types
Leave the Redirect URI blank for now
Click Register
Save Your Application Details After registration, you’ll see the application overview page. Save these values:
Application (client) ID - You’ll need this for authentication
Directory (tenant) ID - You’ll need this for authentication
Keep these IDs secure. Store them in environment variables or Azure Key Vault for production applications, never hardcode them in your source code.
Create a Client Secret
In the left menu, click Certificates & secrets
Click New client secret
Enter a description (e.g., “App Secret”)
Select an expiration period (6 months, 12 months, or 24 months)
Click Add
Important: Copy the secret Value immediately - you won’t be able to see it again!
The client secret is shown only once. If you lose it, you’ll need to create a new one. Store it securely!
Grant API Permissions
In the left menu, click API permissions
Click Add a permission
Select Microsoft Graph
Select Application permissions (not Delegated permissions)
Search for and select User.Read.All
Click Add permissions
Click Grant admin consent for [Your Organization] (requires admin rights)
Confirm by clicking Yes
Application permissions allow your app to access data without a signed-in user. This is perfect for background services and automation. For interactive apps, use Delegated permissions instead.
Install Required Packages
Create a new .NET console application and install the SDK: Create a New Project dotnet new console -n MyGraphApp
cd MyGraphApp
Install Microsoft Graph SDK dotnet add package Microsoft.Graph
Install Azure Identity dotnet add package Azure.Identity
Verify Installation Your .csproj file should now include: < Project Sdk = "Microsoft.NET.Sdk" >
< PropertyGroup >
< OutputType > Exe </ OutputType >
< TargetFramework > net8.0 </ TargetFramework >
</ PropertyGroup >
< ItemGroup >
< PackageReference Include = "Microsoft.Graph" Version = "5.*" />
< PackageReference Include = "Azure.Identity" Version = "1.*" />
</ ItemGroup >
</ Project >
Configure Authentication
Now configure your application to authenticate with Microsoft Graph using the credentials from Step 1. Store Configuration Securely Create an appsettings.json file (add to .gitignore): {
"AzureAd" : {
"TenantId" : "YOUR_TENANT_ID" ,
"ClientId" : "YOUR_CLIENT_ID" ,
"ClientSecret" : "YOUR_CLIENT_SECRET"
}
}
Never commit credentials to source control! Add appsettings.json to your .gitignore file. For production, use Azure Key Vault or environment variables.
Alternative: Use Environment Variables Set environment variables (recommended for production): Windows (PowerShell): $ env: AZURE_TENANT_ID = "your-tenant-id"
$ env: AZURE_CLIENT_ID = "your-client-id"
$ env: AZURE_CLIENT_SECRET = "your-client-secret"
Linux/macOS: export AZURE_TENANT_ID = "your-tenant-id"
export AZURE_CLIENT_ID = "your-client-id"
export AZURE_CLIENT_SECRET = "your-client-secret"
Create GraphServiceClient
Update Program.cs to create and configure the GraphServiceClient: using Azure . Identity ;
using Microsoft . Graph ;
using Microsoft . Graph . Models ;
// Configuration - replace with your values or use environment variables
var tenantId = Environment . GetEnvironmentVariable ( "AZURE_TENANT_ID" ) ?? "YOUR_TENANT_ID" ;
var clientId = Environment . GetEnvironmentVariable ( "AZURE_CLIENT_ID" ) ?? "YOUR_CLIENT_ID" ;
var clientSecret = Environment . GetEnvironmentVariable ( "AZURE_CLIENT_SECRET" ) ?? "YOUR_CLIENT_SECRET" ;
// Create authentication provider
var credential = new ClientSecretCredential ( tenantId , clientId , clientSecret );
// Create Graph client with the default scopes for app-only authentication
var graphClient = new GraphServiceClient ( credential );
Console . WriteLine ( "Microsoft Graph client created successfully!" );
Understanding the Code Let’s break down what’s happening:
ClientSecretCredential - Creates an authentication provider using client credentials flow
GraphServiceClient - The main entry point for all Microsoft Graph operations
The credential handles token acquisition automatically when you make API calls
The SDK automatically uses the scope https://graph.microsoft.com/.default for application permissions, so you don’t need to specify scopes explicitly.
Make Your First API Call
Now let’s retrieve user information from Microsoft Graph! Get a Specific User Add this code to Program.cs: using Azure . Identity ;
using Microsoft . Graph ;
using Microsoft . Graph . Models ;
using Microsoft . Graph . Models . ODataErrors ;
// Configuration
var tenantId = Environment . GetEnvironmentVariable ( "AZURE_TENANT_ID" ) ?? "YOUR_TENANT_ID" ;
var clientId = Environment . GetEnvironmentVariable ( "AZURE_CLIENT_ID" ) ?? "YOUR_CLIENT_ID" ;
var clientSecret = Environment . GetEnvironmentVariable ( "AZURE_CLIENT_SECRET" ) ?? "YOUR_CLIENT_SECRET" ;
// Create Graph client
var credential = new ClientSecretCredential ( tenantId , clientId , clientSecret );
var graphClient = new GraphServiceClient ( credential );
try
{
Console . WriteLine ( "Fetching users from Microsoft Graph... \n " );
// Get the first 5 users
var users = await graphClient . Users . GetAsync ( requestConfiguration =>
{
requestConfiguration . QueryParameters . Top = 5 ;
requestConfiguration . QueryParameters . Select = new [] { "displayName" , "mail" , "userPrincipalName" };
requestConfiguration . QueryParameters . OrderBy = new [] { "displayName" };
});
if ( users ? . Value != null && users . Value . Count > 0 )
{
Console . WriteLine ( $"Found { users . Value . Count } users: \n " );
foreach ( var user in users . Value )
{
Console . WriteLine ( $"Name: { user . DisplayName } " );
Console . WriteLine ( $"Email: { user . Mail ?? user . UserPrincipalName } " );
Console . WriteLine ( $"UPN: { user . UserPrincipalName } " );
Console . WriteLine ();
}
}
else
{
Console . WriteLine ( "No users found." );
}
}
catch ( ODataError odataError )
{
Console . WriteLine ( $"Error calling Microsoft Graph:" );
Console . WriteLine ( $"Code: { odataError . Error ? . Code } " );
Console . WriteLine ( $"Message: { odataError . Error ? . Message } " );
}
catch ( Exception ex )
{
Console . WriteLine ( $"Unexpected error: { ex . Message } " );
}
Run Your Application Expected Output Fetching users from Microsoft Graph...
Found 5 users:
Name: Alice Johnson
Email: alice@contoso.com
UPN: alice@contoso.com
Name: Bob Smith
Email: bob@contoso.com
UPN: bob@contoso.com
Name: Carol Williams
Email: carol@contoso.com
UPN: carol@contoso.com
If you see an authentication error, double-check that you granted admin consent for the User.Read.All permission in the Azure Portal.
Complete Working Example
Here’s the complete, production-ready code with error handling and best practices:
Program.cs
MyGraphApp.csproj
.gitignore
using Azure . Identity ;
using Microsoft . Graph ;
using Microsoft . Graph . Models ;
using Microsoft . Graph . Models . ODataErrors ;
using System ;
using System . Threading . Tasks ;
namespace MyGraphApp
{
class Program
{
static async Task Main ( string [] args )
{
// Load configuration from environment variables
var tenantId = Environment . GetEnvironmentVariable ( "AZURE_TENANT_ID" );
var clientId = Environment . GetEnvironmentVariable ( "AZURE_CLIENT_ID" );
var clientSecret = Environment . GetEnvironmentVariable ( "AZURE_CLIENT_SECRET" );
// Validate configuration
if ( string . IsNullOrEmpty ( tenantId ) ||
string . IsNullOrEmpty ( clientId ) ||
string . IsNullOrEmpty ( clientSecret ))
{
Console . WriteLine ( "Error: Missing required environment variables." );
Console . WriteLine ( "Please set AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET" );
return ;
}
try
{
// Create Graph client
var credential = new ClientSecretCredential ( tenantId , clientId , clientSecret );
var graphClient = new GraphServiceClient ( credential );
Console . WriteLine ( "Microsoft Graph .NET SDK Quick Start" );
Console . WriteLine ( "===================================== \n " );
// Get users
await GetUsersAsync ( graphClient );
// Get groups
await GetGroupsAsync ( graphClient );
}
catch ( Exception ex )
{
Console . WriteLine ( $"Fatal error: { ex . Message } " );
}
}
static async Task GetUsersAsync ( GraphServiceClient graphClient )
{
try
{
Console . WriteLine ( "Fetching users... \n " );
var users = await graphClient . Users . GetAsync ( requestConfiguration =>
{
requestConfiguration . QueryParameters . Top = 5 ;
requestConfiguration . QueryParameters . Select =
new [] { "displayName" , "mail" , "userPrincipalName" , "jobTitle" };
requestConfiguration . QueryParameters . OrderBy = new [] { "displayName" };
});
if ( users ? . Value != null )
{
Console . WriteLine ( $"Found { users . Value . Count } users: \n " );
foreach ( var user in users . Value )
{
Console . WriteLine ( $" { user . DisplayName } " );
Console . WriteLine ( $" Email: { user . Mail ?? user . UserPrincipalName } " );
if ( ! string . IsNullOrEmpty ( user . JobTitle ))
{
Console . WriteLine ( $" Title: { user . JobTitle } " );
}
Console . WriteLine ();
}
}
}
catch ( ODataError odataError )
{
Console . WriteLine ( $"Error fetching users:" );
Console . WriteLine ( $" Code: { odataError . Error ? . Code } " );
Console . WriteLine ( $" Message: { odataError . Error ? . Message } " );
Console . WriteLine ();
}
}
static async Task GetGroupsAsync ( GraphServiceClient graphClient )
{
try
{
Console . WriteLine ( "Fetching groups... \n " );
var groups = await graphClient . Groups . GetAsync ( requestConfiguration =>
{
requestConfiguration . QueryParameters . Top = 5 ;
requestConfiguration . QueryParameters . Select =
new [] { "displayName" , "description" , "mailEnabled" };
requestConfiguration . QueryParameters . OrderBy = new [] { "displayName" };
});
if ( groups ? . Value != null )
{
Console . WriteLine ( $"Found { groups . Value . Count } groups: \n " );
foreach ( var group in groups . Value )
{
Console . WriteLine ( $" { group . DisplayName } " );
if ( ! string . IsNullOrEmpty ( group . Description ))
{
Console . WriteLine ( $" Description: { group . Description } " );
}
Console . WriteLine ( $" Mail Enabled: { group . MailEnabled } " );
Console . WriteLine ();
}
}
}
catch ( ODataError odataError )
{
Console . WriteLine ( $"Error fetching groups:" );
Console . WriteLine ( $" Code: { odataError . Error ? . Code } " );
Console . WriteLine ( $" Message: { odataError . Error ? . Message } " );
Console . WriteLine ();
}
}
}
}
Understanding Query Parameters
The SDK provides a fluent API for adding query parameters:
var users = await graphClient . Users . GetAsync ( requestConfiguration =>
{
// Limit number of results
requestConfiguration . QueryParameters . Top = 10 ;
// Select specific properties
requestConfiguration . QueryParameters . Select = new [] { "displayName" , "mail" };
// Filter results
requestConfiguration . QueryParameters . Filter = "startswith(displayName,'A')" ;
// Sort results
requestConfiguration . QueryParameters . OrderBy = new [] { "displayName" };
// Add custom headers (e.g., for consistency level)
requestConfiguration . Headers . Add ( "ConsistencyLevel" , "eventual" );
});
Common API Calls
Here are more examples of common operations:
Get Current User (Delegated Permissions)
// Only works with delegated permissions (interactive auth)
var me = await graphClient . Me . GetAsync ();
Console . WriteLine ( $"Signed in as: { me . DisplayName } " );
Get User’s Messages
var messages = await graphClient . Users [ "user-id" ]. Messages . GetAsync ( requestConfiguration =>
{
requestConfiguration . QueryParameters . Top = 10 ;
requestConfiguration . QueryParameters . Select =
new [] { "subject" , "from" , "receivedDateTime" };
requestConfiguration . QueryParameters . OrderBy =
new [] { "receivedDateTime DESC" };
});
foreach ( var message in messages . Value )
{
Console . WriteLine ( $"Subject: { message . Subject } " );
Console . WriteLine ( $"From: { message . From ? . EmailAddress ? . Address } " );
Console . WriteLine ( $"Received: { message . ReceivedDateTime } " );
Console . WriteLine ();
}
Get User’s Calendar Events
var events = await graphClient . Users [ "user-id" ]. Events . GetAsync ( requestConfiguration =>
{
requestConfiguration . QueryParameters . Top = 10 ;
requestConfiguration . QueryParameters . Select =
new [] { "subject" , "start" , "end" , "organizer" };
requestConfiguration . QueryParameters . OrderBy = new [] { "start/dateTime" };
});
foreach ( var evt in events . Value )
{
Console . WriteLine ( $"Event: { evt . Subject } " );
Console . WriteLine ( $"Start: { evt . Start ? . DateTime } " );
Console . WriteLine ( $"End: { evt . End ? . DateTime } " );
Console . WriteLine ();
}
Get User’s OneDrive Files
// Get the user's drive
var drive = await graphClient . Users [ "user-id" ]. Drive . GetAsync ();
var driveId = drive . Id ;
// Get root folder items
var items = await graphClient . Drives [ driveId ]. Items [ "root" ]. Children . GetAsync ();
foreach ( var item in items . Value )
{
Console . WriteLine ( $"Name: { item . Name } " );
Console . WriteLine ( $"Type: {( item . Folder != null ? "Folder" : "File" )} " );
Console . WriteLine ( $"Size: { item . Size } bytes" );
Console . WriteLine ();
}
Troubleshooting
Authentication Failed
Error: 401 Unauthorized or AADSTS700016: Application not found
Solution:
Verify your tenant ID, client ID, and client secret are correct
Ensure you granted admin consent for the required permissions
Check that the application is enabled in Azure AD
Insufficient Privileges
Error: 403 Forbidden or Insufficient privileges to complete the operation
Solution:
Verify you granted the correct API permissions (e.g., User.Read.All)
Ensure you clicked “Grant admin consent” in the Azure Portal
Wait a few minutes for permissions to propagate
User Not Found
Error: 404 Not Found or Resource not found for the segment 'users'
Solution:
Verify the user ID or UPN is correct
Ensure the user exists in your tenant
Check that your app has permission to read users
Next Steps
Congratulations! You’ve successfully built your first Microsoft Graph application. Here’s what to explore next:
Authentication Methods Learn about interactive authentication, device code flow, and more
Core Concepts Understand request builders, models, and collections in depth
Error Handling Learn best practices for handling errors and retries
Working with Collections Master paging, filtering, and working with large result sets
Additional Resources