All skills
github avatar

/msgraph-sdk

@8bd33a9 official
by githubgithub/awesome-copilot40k stars
5,040

Integrate Microsoft Graph SDK into any project — .NET, TypeScript/JavaScript, or Python. Covers auth patterns (client credentials, OBO, managed identity), SDK setup, calling Graph APIs, batching, delta queries, change notifications, throttling, and permission scopes. Use when accessing Microsoft 365 data (users, mail, calendar, Teams, files, SharePoint) from any application type.

Use this Skill: https://skilld.dev/gh/github/awesome-copilot/msgraph-sdk

This session only. Nothing lands on disk.

referencesdotnet.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Microsoft Graph SDK for .NET

Use this reference when the target project is written in C# or another .NET language.

Authoritative sources

Packages

<!-- Microsoft Graph SDK v5 (current) -->
<PackageReference Include="Microsoft.Graph" Version="5.*" />

<!-- Azure Identity for credential providers -->
<PackageReference Include="Azure.Identity" Version="1.*" />

Install via CLI:

dotnet add package Microsoft.Graph
dotnet add package Azure.Identity

Client setup

Managed Identity (Azure-hosted apps — preferred)

using Azure.Identity;
using Microsoft.Graph;

var credential = new DefaultAzureCredential();
var graphClient = new GraphServiceClient(credential);

Client credentials (app-only / daemon)

var credential = new ClientSecretCredential(
    tenantId: Environment.GetEnvironmentVariable("AZURE_TENANT_ID"),
    clientId: Environment.GetEnvironmentVariable("AZURE_CLIENT_ID"),
    clientSecret: Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET")
);
var graphClient = new GraphServiceClient(credential);

Prefer ClientCertificateCredential over ClientSecretCredential in production.

On-Behalf-Of (OBO) — agent / API acting as the signed-in user

// incomingToken is the bearer token received from the caller
var credential = new OnBehalfOfCredential(
    tenantId: Environment.GetEnvironmentVariable("AZURE_TENANT_ID"),
    clientId: Environment.GetEnvironmentVariable("AZURE_CLIENT_ID"),
    clientSecret: Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET"),
    userAssertion: new UserAssertion(incomingToken)
);
var graphClient = new GraphServiceClient(credential);

Interactive (local dev / CLI)

var credential = new InteractiveBrowserCredential();
var graphClient = new GraphServiceClient(credential);

Common call patterns

Get a resource with field selection

var user = await graphClient.Me.GetAsync(config =>
{
    config.QueryParameters.Select = ["displayName", "mail", "jobTitle"];
});

List with filter and select

var messages = await graphClient.Me.Messages.GetAsync(config =>
{
    config.QueryParameters.Filter = "isRead eq false";
    config.QueryParameters.Select = ["subject", "from", "receivedDateTime"];
    config.QueryParameters.Top = 25;
    config.QueryParameters.Orderby = ["receivedDateTime desc"];
});

Pagination with PageIterator

var messages = await graphClient.Me.Messages.GetAsync();

var allMessages = new List<Message>();
var pageIterator = PageIterator<Message, MessageCollectionResponse>
    .CreatePageIterator(graphClient, messages, (msg) =>
    {
        allMessages.Add(msg);
        return true; // return false to stop early
    });

await pageIterator.IterateAsync();

Send an email

await graphClient.Me.SendMail.PostAsync(new SendMailPostRequestBody
{
    Message = new Message
    {
        Subject = "Hello from Graph",
        Body = new ItemBody { ContentType = BodyType.Text, Content = "Test message" },
        ToRecipients = [new Recipient { EmailAddress = new EmailAddress { Address = "user@contoso.com" } }]
    }
});

Post a Teams channel message

await graphClient.Teams[teamId].Channels[channelId].Messages.PostAsync(new ChatMessage
{
    Body = new ItemBody { ContentType = BodyType.Html, Content = "<b>Hello from Graph!</b>" }
});

Batch requests

using Microsoft.Graph.Models;

var batchRequestContent = new BatchRequestContentCollection(graphClient);

var meRequest = await batchRequestContent.AddBatchRequestStepAsync(
    graphClient.Me.ToGetRequestInformation());
var messagesRequest = await batchRequestContent.AddBatchRequestStepAsync(
    graphClient.Me.Messages.ToGetRequestInformation());

var batchResponse = await graphClient.Batch.PostAsync(batchRequestContent);

var me = await batchResponse.GetResponseByIdAsync<User>(meRequest);
var msgs = await batchResponse.GetResponseByIdAsync<MessageCollectionResponse>(messagesRequest);

Delta queries

// First sync — get all + deltaLink
var deltaResponse = await graphClient.Users.Delta.GetAsDeltaGetResponseAsync();
string? deltaLink = null;

var pageIterator = PageIterator<User, Microsoft.Graph.Users.Delta.DeltaGetResponse>
    .CreatePageIterator(graphClient, deltaResponse, (user) => { /* process */ return true; },
        (req) => { deltaLink = /* extract from response */; return req; });

await pageIterator.IterateAsync();
// Store deltaLink for next run

// Subsequent sync — only changes
// Use the stored deltaLink directly as the next request URL

Throttling / retry middleware

The SDK includes retry middleware enabled by default. For explicit control:

var handlers = GraphClientFactory.CreateDefaultHandlers();
// RetryHandler is included; configure max retries if needed
var httpClient = GraphClientFactory.Create(handlers);
var graphClient = new GraphServiceClient(httpClient, credential);

Always check Retry-After if building custom retry logic — do not use fixed exponential backoff.

Dependency injection (ASP.NET Core / .NET Worker)

// Program.cs
builder.Services.AddSingleton<GraphServiceClient>(_ =>
{
    var credential = new DefaultAzureCredential();
    return new GraphServiceClient(credential);
});

.NET-specific guidance

  • Target .NET 8+ for new projects.
  • Use async/await throughout — all Graph SDK calls are async.
  • Register GraphServiceClient as a singleton (it caches tokens internally).
  • Use ILogger to log Graph exceptions — catch ODataError for Graph-specific error details.
  • For ASP.NET Core APIs using OBO, inject the incoming token from IHttpContextAccessor and construct the credential per-request (not as a singleton).
// Catching Graph errors
try
{
    var user = await graphClient.Me.GetAsync();
}
catch (ODataError odataError)
{
    Console.WriteLine($"Graph error: {odataError.Error?.Code} - {odataError.Error?.Message}");
}

Source: SKILL.md on GitHub

No alerts3mo3 checks · Risk SAFE
  • Gen Agent Trust Hub3mo

    This skill provides safe and authoritative guidance for integrating the Microsoft Graph SDK into .NET, Python, and TypeScript projects. It strictly follows security best practices, including the use of Managed Identities, environment variables for secret management, and enforcing the principle of least privilege for API permissions. All external resources and packages originate from official Microsoft repositories and well-known registries.

  • Socket3mo

    No alerts

  • Snyk3mo

    Risk: LOW · No issues

Signed by skilld at 8bd33a9. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 5 months ago
  • TypeScript
  • Python
  • microsoft-graph
  • msgraph-sdk
  • microsoft-365
  • authentication
  • dotnet
  • api-integration
  • pagination
  • throttling

README badge

README badge for github/awesome-copilot/msgraph-sdk

Integrates Microsoft Graph SDK for .NET, TypeScript/JavaScript, or Python to access Microsoft 365 data (users, mail, calendar, Teams, files, SharePoint). Covers authentication patterns (client credentials, on-behalf-of, managed identity), pagination, batching, delta queries, change notifications, throttling, and permission scopes.

Generated from the current SKILL.md.

Does this skill support all three languages — .NET, TypeScript, and Python?
Yes. The skill includes language-specific reference workflows for .NET, TypeScript/JavaScript, and Python. Follow the matching reference file based on your project's file types.
Which authentication flow should I use for a background service?
Use client credentials (app-only) for background services or daemons with no user context. The skill includes a decision tree to match your scenario to the correct auth pattern.
How do I handle pagination when fetching large collections from Graph?
Always check for `@odata.nextLink` in responses and use the SDK's `PageIterator` helper to walk pages automatically. Never assume all items arrive in one request.
What should I do if I receive HTTP 429 (throttling) responses?
Read the `Retry-After` header for the exact wait time, and enable the SDK's built-in retry middleware to handle 429s automatically. Avoid parallel fan-out patterns; use batching or queuing instead.
Does this skill cover change notifications and webhooks?
Yes. The skill covers subscription creation, validation handshakes, renewal before expiration, and lifecycle notifications for handling missed events.

Generated from the current SKILL.md. These answers refresh after source changes.