Microsoft Graph SDK Authentication in C#: Quick Start Guide

Jun 20, 2025 min read

What is Microsoft Graph?

Microsoft Graph is the unified REST API for Microsoft 365. Think of it as a single gateway to access data across SharePoint, Teams, OneDrive, Outlook, Azure AD, and more - all through one consistent API.

Graph vs CSOM/PnP.Framework:

  • Graph: Modern REST API, works across all Microsoft 365 services
  • CSOM/PnP: SharePoint-specific, more SharePoint features available

When to Use Graph SDK vs PnP.Framework

✅ Use Graph SDK when:

  • Building modern cloud applications
  • Need access to Teams, OneDrive, Exchange, or Azure AD
  • Want built-in retry logic, batching, and performance optimizations
  • Building apps that integrate multiple Microsoft 365 services

✅ Use PnP.Framework when:

  • Need advanced SharePoint features (site templates, provisioning, taxonomy)
  • Working with SharePoint-specific APIs not yet in Graph
  • Building SharePoint-focused solutions
  • Need features like search refiners, managed metadata, or custom actions

❌ Graph SDK limitations:

  • No support for SharePoint classic features (master pages, web parts)
  • Limited search capabilities compared to SharePoint Search API
  • Some advanced list/library features not available
  • Can’t access SharePoint on-premises (SharePoint Server)

Quick Start

Building on the PnP.Framework authentication setup, let’s add Microsoft Graph SDK to access all Microsoft 365 services with the same certificate.

Add Graph Permissions

In your existing app registration, go to “API permissions” → “Add a permission” → “Microsoft Graph” → “Application permissions”:

  • Sites.ReadWrite.All: SharePoint sites and lists access

Important: Click “Grant admin consent” after adding permissions!

Install and Code

Install the NuGet package:

Install-Package Microsoft.Graph

Here’s the same example from the PnP.Framework post, but using Graph SDK:

using Microsoft.Graph;
using Microsoft.Graph.Auth;
using System.Security.Cryptography.X509Certificates;

class Program
{
    private static readonly string TenantId = "your-tenant-id";
    private static readonly string ClientId = "your-client-id";
    private static readonly string CertificatePath = @"C:\Temp\cert\pnpappcert.pfx";
    private static readonly string CertificatePassword = "MySuperStrongPassword!";

    static async Task Main(string[] args)
    {
        // Create Graph client (same certificate as PnP.Framework)
        var certificate = new X509Certificate2(CertificatePath, CertificatePassword);
        var options = new ClientCertificateCredentialOptions
        {
            AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
        };

        var clientCertCredential = new ClientCertificateCredential(
            TenantId, ClientId, certificate, options);

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

        var graphClient = new GraphServiceClient(clientCertCredential, scopes);

        // Test connection
        var org = await graphClient.Organization.Request().GetAsync();
        Console.WriteLine($"Connected to: {org.First().DisplayName}");

        // Get all lists (like PnP.Framework example)
        var site = await graphClient.Sites["root"].Request().GetAsync();
        var lists = await graphClient.Sites[site.Id].Lists.Request().GetAsync();
        
        Console.WriteLine("Lists in this site:");
        foreach (var list in lists)
        {
            Console.WriteLine($"- {list.DisplayName}");
        }

        // Upload a document (like PnP.Framework example)
        var docLib = lists.FirstOrDefault(l => l.DisplayName == "Documents");
        if (docLib != null)
        {
            var content = System.Text.Encoding.UTF8.GetBytes("Hello from Graph SDK!");
            var drive = await graphClient.Sites[site.Id].Lists[docLib.Id].Drive.Request().GetAsync();
            
            var file = await graphClient.Drives[drive.Id].Root
                .ItemWithPath("sample-document.txt")
                .Content
                .Request()
                .PutAsync<DriveItem>(new MemoryStream(content));
            
            Console.WriteLine($"Uploaded file: {file.Name}");
        }
    }
}

Key Differences from PnP.Framework

Same operations, different syntax:

Operation PnP.Framework Graph SDK
Get Lists context.Web.Lists graphClient.Sites[id].Lists
Upload File docLib.RootFolder.Files.Add() drive.Root.ItemWithPath().Content.Put()
Authentication AuthenticationManager ClientCertificateProvider

Graph advantages: Access to Teams, OneDrive, Exchange data with same client
PnP advantages: More SharePoint-specific features like content types, site columns

Troubleshooting

  • “Insufficient privileges”: Check permissions and admin consent
  • “Certificate not found”: Verify certificate path and password
  • “Unauthorized”: Ensure app has correct Graph permissions

Next Steps

You now have Graph SDK working with your existing app registration! With the basic setup, you can:

  • Access SharePoint sites and lists
  • Upload and manage files in document libraries
  • Get organization information

To access more Microsoft 365 services, add the appropriate permissions:

  • User.Read.All for user data
  • Group.Read.All for Teams and groups
  • Files.ReadWrite.All for broader file operations
  • Mail.Read for Exchange data

Perfect foundation for building comprehensive Microsoft 365 integrations.

References

Jeppe Spanggaard

A passionate software developer. I love to build software that makes a difference!