Microsoft Graph Developer Referenz Microsoft Graph Developer Reference
Vollständige Entwicklerreferenz für Microsoft Graph – SDKs (.NET, JS, Java, Python, Go, PHP, PowerShell), Authentifizierungsmuster, erweiterte Abfragen, Batch, Delta, Webhooks, Pagination, Throttling, Data Connect, Connectors und Graph Toolkit. Complete developer reference for Microsoft Graph – SDKs (.NET, JS, Java, Python, Go, PHP, PowerShell), authentication patterns, advanced queries, batch, delta, webhooks, pagination, throttling, Data Connect, connectors, and Graph Toolkit.
Die offiziellen Graph-SDKs übernehmen automatisch Authentifizierung (via MSAL), Retry-Logik bei Throttling (429), Pagination über @odata.nextLink, und bieten typisierte Modelle. Direkter HTTP-Zugriff ist nur für Tests mit Graph Explorer oder beim Prototyping sinnvoll. The official Graph SDKs automatically handle authentication (via MSAL), retry logic on throttling (429), pagination via @odata.nextLink, and provide typed models. Direct HTTP access is only useful for testing with Graph Explorer or during prototyping.
.NET, JS, Java, Python, Go, PHP, PowerShell .NET, JS, Java, Python, Go, PHP, PowerShell
Delegiert, App-only, OBO, Client Credentials Delegated, app-only, OBO, client credentials
$filter, $search, ConsistencyLevel, OData $filter, $search, ConsistencyLevel, OData
JSON-Batching, bis zu 20 Anfragen JSON batching, up to 20 requests
Inkrementelle Änderungsverfolgung Incremental change tracking
Change Notifications, Rich Notifications Change notifications, rich notifications
@odata.nextLink, Retry-After @odata.nextLink, Retry-After
Graph Toolkit, Graph Explorer, Data Connect Graph Toolkit, Graph Explorer, Data Connect
SDK-Übersicht SDK overview
Microsoft stellt offiziell unterstützte Graph-SDKs für sieben Plattformen bereit. Alle SDKs werden aus dem OpenAPI-Schema der Graph-API automatisch generiert und folgen einem einheitlichen Programmiermodell: Fluent API, typisierte Modelle, eingebaute Retry-Logik und Middleware-Architektur. Microsoft provides officially supported Graph SDKs for seven platforms. All SDKs are automatically generated from the Graph API OpenAPI schema and follow a consistent programming model: fluent API, typed models, built-in retry logic, and middleware architecture.
| Sprache / PlattformLanguage / Platform | PaketPackage | InstallationInstall | GitHubGitHub |
|---|---|---|---|
| .NET (C#).NET (C#) | Microsoft.GraphMicrosoft.Graph |
dotnet add package Microsoft.Graphdotnet add package Microsoft.Graph |
microsoftgraph/msgraph-sdk-dotnetmicrosoftgraph/msgraph-sdk-dotnet |
| JavaScript / TypeScriptJavaScript / TypeScript | @microsoft/microsoft-graph-client@microsoft/microsoft-graph-client |
npm install @microsoft/microsoft-graph-clientnpm install @microsoft/microsoft-graph-client |
microsoftgraph/msgraph-sdk-javascriptmicrosoftgraph/msgraph-sdk-javascript |
| JavaJava | com.microsoft.graph:microsoft-graphcom.microsoft.graph:microsoft-graph |
Maven / Gradle DependencyMaven / Gradle dependency | microsoftgraph/msgraph-sdk-javamicrosoftgraph/msgraph-sdk-java |
| PythonPython | msgraph-sdkmsgraph-sdk |
pip install msgraph-sdkpip install msgraph-sdk |
microsoftgraph/msgraph-sdk-pythonmicrosoftgraph/msgraph-sdk-python |
| GoGo | github.com/microsoftgraph/msgraph-sdk-gogithub.com/microsoftgraph/msgraph-sdk-go |
go get github.com/microsoftgraph/msgraph-sdk-gogo get github.com/microsoftgraph/msgraph-sdk-go |
microsoftgraph/msgraph-sdk-gomicrosoftgraph/msgraph-sdk-go |
| PHPPHP | microsoft/microsoft-graphmicrosoft/microsoft-graph |
composer require microsoft/microsoft-graphcomposer require microsoft/microsoft-graph |
microsoftgraph/msgraph-sdk-phpmicrosoftgraph/msgraph-sdk-php |
| PowerShellPowerShell | Microsoft.GraphMicrosoft.Graph |
Install-Module Microsoft.GraphInstall-Module Microsoft.Graph |
microsoftgraph/msgraph-sdk-powershellmicrosoftgraph/msgraph-sdk-powershell |
.NET SDK (C#) .NET SDK (C#)
Das .NET Graph SDK v5+ verwendet das neue Kiota-generierte Clientmodell mit einer vollständig fluenten API. Die Authentifizierung erfolgt über Azure.Identity mit TokenCredential-Providern, die nahtlos für Managed Identity, Service Principal und interaktive Flows funktionieren.
The .NET Graph SDK v5+ uses the new Kiota-generated client model with a fully fluent API. Authentication uses Azure.Identity with TokenCredential providers that work seamlessly for managed identity, service principal, and interactive flows.
# Pakete installieren (.NET CLI)
dotnet add package Microsoft.Graph
dotnet add package Azure.Identity
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Models;
// App-only Authentication (Service Principal / Client Credentials)
var credential = new ClientSecretCredential(
tenantId: Environment.GetEnvironmentVariable("AZURE_TENANT_ID"),
clientId: Environment.GetEnvironmentVariable("AZURE_CLIENT_ID"),
clientSecret: Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET")
);
// GraphServiceClient mit Default-Scopes
var graphClient = new GraphServiceClient(credential,
new[] { "https://graph.microsoft.com/.default" });
// Benutzer abrufen mit $select, $filter, $top
var users = await graphClient.Users.GetAsync(req =>
{
req.QueryParameters.Select = new[] { "id", "displayName", "userPrincipalName", "department" };
req.QueryParameters.Filter = "department eq 'Engineering'";
req.QueryParameters.Top = 20;
req.QueryParameters.Orderby = new[] { "displayName asc" };
});
foreach (var user in users?.Value ?? new List<User>())
{
Console.WriteLine($"{user.DisplayName,-40} {user.UserPrincipalName}");
}
// Managed Identity (Azure Functions, App Service, VM)
var managedCred = new ManagedIdentityCredential();
var mgClient = new GraphServiceClient(managedCred,
new[] { "https://graph.microsoft.com/.default" });
// Einzelnen Benutzer per Id abrufen
var singleUser = await mgClient.Users["alice@contoso.com"].GetAsync();
Console.WriteLine($"UPN: {singleUser?.UserPrincipalName}");
// Benutzer erstellen
var newUser = new User
{
DisplayName = "Bob Müller",
UserPrincipalName = "bob@contoso.com",
MailNickname = "bob",
AccountEnabled = true,
PasswordProfile = new PasswordProfile
{
Password = "TempP@ssw0rd!",
ForceChangePasswordNextSignIn = true
}
};
var createdUser = await graphClient.Users.PostAsync(newUser);
JavaScript / TypeScript SDK JavaScript / TypeScript SDK
Das JavaScript SDK unterstützt sowohl Browser- als auch Node.js-Szenarien. Für Browser-Anwendungen wird @azure/msal-browser verwendet, für Node.js-Services @azure/msal-node. Das SDK unterstützt automatisches Retry, Response-Middleware und TypeScript-Typen.
The JavaScript SDK supports both browser and Node.js scenarios. For browser applications use @azure/msal-browser, for Node.js services use @azure/msal-node. The SDK supports automatic retry, response middleware, and TypeScript types.
# Node.js (npm)
npm install @microsoft/microsoft-graph-client @azure/identity isomorphic-fetch
# Browser (npm + bundler)
npm install @microsoft/microsoft-graph-client @azure/msal-browser
import "isomorphic-fetch";
import { Client } from "@microsoft/microsoft-graph-client";
import { TokenCredentialAuthenticationProvider } from
"@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
import { ClientSecretCredential } from "@azure/identity";
// App-only auth für Node.js
const credential = new ClientSecretCredential(
process.env.AZURE_TENANT_ID,
process.env.AZURE_CLIENT_ID,
process.env.AZURE_CLIENT_SECRET
);
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
scopes: ["https://graph.microsoft.com/.default"]
});
const client = Client.initWithMiddleware({ authProvider });
// Benutzer mit Pagination abrufen
async function getAllUsers() {
const allUsers = [];
let response = await client.api("/users")
.select("id,displayName,userPrincipalName,department")
.filter("accountEnabled eq true")
.top(100)
.get();
allUsers.push(...response.value);
// Automatische Pagination
while (response["@odata.nextLink"]) {
response = await client.api(response["@odata.nextLink"]).get();
allUsers.push(...response.value);
}
return allUsers;
}
// Teams-Kanal-Nachricht senden
async function sendTeamsMessage(teamId, channelId, message) {
await client.api(`/teams/${teamId}/channels/${channelId}/messages`).post({
body: { content: message, contentType: "html" }
});
}
// Benutzerfotos als Blob herunterladen
async function getUserPhoto(userId) {
const photo = await client.api(`/users/${userId}/photo/$value`)
.responseType("blob")
.get();
return URL.createObjectURL(photo);
}
const users = await getAllUsers();
console.log(`Total users: ${users.length}`);
Python SDK Python SDK
Das Python Graph SDK (basierend auf Kiota) bietet eine vollständig typisierte async/await-fähige Client-Bibliothek. Es verwendet azure-identity für die Authentifizierung und unterstützt alle Graph-Endpunkte mit generierten Modellen.
The Python Graph SDK (based on Kiota) provides a fully typed async/await-capable client library. It uses azure-identity for authentication and supports all Graph endpoints with generated models.
pip install msgraph-sdk azure-identity
import asyncio
from azure.identity.aio import ClientSecretCredential
from msgraph import GraphServiceClient
from msgraph.generated.users.users_request_builder import UsersRequestBuilder
from kiota_abstractions.base_request_configuration import RequestConfiguration
async def main():
credential = ClientSecretCredential(
tenant_id = "YOUR_TENANT_ID",
client_id = "YOUR_CLIENT_ID",
client_secret = "YOUR_CLIENT_SECRET"
)
scopes = ["https://graph.microsoft.com/.default"]
client = GraphServiceClient(credentials=credential, scopes=scopes)
# Benutzer mit $select und $filter abfragen
query_params = UsersRequestBuilder.UsersRequestBuilderGetQueryParameters(
select = ["id", "displayName", "userPrincipalName", "department"],
filter = "department eq 'Engineering'",
top = 50,
orderby = ["displayName asc"]
)
config = RequestConfiguration(query_parameters=query_params)
users = await client.users.get(request_configuration=config)
for user in users.value:
print(f"{user.display_name:<40} {user.user_principal_name}")
# Gruppen eines Benutzers abrufen
groups = await client.users.by_user_id("alice@contoso.com").member_of.get()
group_names = [g.display_name for g in groups.value if hasattr(g, "display_name")]
print(f"Gruppen: {', '.join(group_names)}")
# Benutzer aktualisieren
from msgraph.generated.models.user import User
patch = User(department="IT Security")
await client.users.by_user_id("alice@contoso.com").patch(patch)
await credential.close()
asyncio.run(main())
Authentifizierungsmuster Authentication patterns
Microsoft Graph verwendet OAuth 2.0 und OpenID Connect. Je nach Szenario kommt ein anderer Flow zum Einsatz: Delegierte Berechtigung für interaktive Benutzeranwendungen, App-only für Hintergrunddienste, On-Behalf-Of (OBO) für Middle-Tier-Services die im Namen des Benutzers handeln. Microsoft Graph uses OAuth 2.0 and OpenID Connect. Different flows apply depending on the scenario: delegated permission for interactive user applications, app-only for background services, On-Behalf-Of (OBO) for middle-tier services acting on behalf of the user.
| FlowFlow | AnwendungsfallUse case | Token-TypToken type | BerechtigungstypPermission type |
|---|---|---|---|
| Authorization CodeAuthorization code | Web-App mit BenutzeranmeldungWeb app with user sign-in | Access + Refresh TokenAccess + refresh token | DelegiertDelegated |
| Client CredentialsClient credentials | Hintergrunddienst, Daemon, Azure FunctionBackground service, daemon, Azure Function | Access Token (kein User)Access token (no user) | AnwendungApplication |
| On-Behalf-Of (OBO)On-Behalf-Of (OBO) | API-zu-API-Aufruf im BenutzerkontextAPI-to-API call in user context | Delegation-TokenDelegation token | Delegiert (propagiert)Delegated (propagated) |
| Device CodeDevice code | CLI / IoT-Gerät ohne BrowserCLI / IoT device without browser | Access + Refresh TokenAccess + refresh token | DelegiertDelegated |
| Managed IdentityManaged identity | Azure-Ressource (VM, App Service, Function)Azure resource (VM, App Service, Function) | Access Token (kein Geheimnis)Access token (no secret) | AnwendungApplication |
| Workload Identity FederationWorkload identity federation | GitHub Actions, AKS Workload IdentityGitHub Actions, AKS Workload Identity | Federated TokenFederated token | Anwendung (secretless)Application (secretless) |
using Azure.Identity;
using Microsoft.Graph;
// System-Assigned Managed Identity
var miCredential = new ManagedIdentityCredential();
var miClient = new GraphServiceClient(miCredential,
new[] { "https://graph.microsoft.com/.default" });
// User-Assigned Managed Identity
var uamiCredential = new ManagedIdentityCredential(
clientId: "00000000-0000-0000-0000-000000000001");
var uamiClient = new GraphServiceClient(uamiCredential,
new[] { "https://graph.microsoft.com/.default" });
// Workload Identity Federation (GitHub Actions, AKS)
// AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE automatisch von OIDC gesetzt
var wifCredential = new WorkloadIdentityCredential();
var wifClient = new GraphServiceClient(wifCredential,
new[] { "https://graph.microsoft.com/.default" });
// Certificate-basierte App-Authentifizierung (empfohlen statt Client Secret)
var certCredential = new ClientCertificateCredential(
tenantId: Environment.GetEnvironmentVariable("AZURE_TENANT_ID"),
clientId: Environment.GetEnvironmentVariable("AZURE_CLIENT_ID"),
certificate: System.Security.Cryptography.X509Certificates.X509Certificate2
.CreateFromPemFile("certificate.pem", "private-key.pem")
);
var certClient = new GraphServiceClient(certCredential,
new[] { "https://graph.microsoft.com/.default" });
Erweiterte Abfragen (Advanced Query Capabilities) Advanced queries (Advanced Query Capabilities)
Graph unterstützt OData-Abfrageparameter wie $filter, $select, $expand, $search, $orderby und $count. Erweiterte Filterfunktionen (wie endsWith, not, ne auf Nicht-Pflichtfeldern) erfordern den Header ConsistencyLevel: eventual und in der Regel $count=true.
Graph supports OData query parameters such as $filter, $select, $expand, $search, $orderby, and $count. Advanced filter functions (such as endsWith, not, ne on non-indexed fields) require the header ConsistencyLevel: eventual and typically $count=true.
| ParameterParameter | ZweckPurpose | BeispielExample |
|---|---|---|
$filter$filter |
Serverseitige FilterungServer-side filtering | $filter=department eq 'IT'$filter=department eq 'IT' |
$select$select |
Felder einschränkenRestrict fields | $select=id,displayName,mail$select=id,displayName,mail |
$expand$expand |
Beziehungen einbettenEmbed relationships | $expand=members($select=id,displayName)$expand=members($select=id,displayName) |
$search$search |
Volltextsuche (Persons, Drive)Full-text search (Persons, Drive) | $search="displayName:Alice"$search="displayName:Alice" |
$orderby$orderby |
SortierungSorting | $orderby=displayName asc$orderby=displayName asc |
$count=true$count=true |
Gesamtanzahl zurückgebenReturn total count | Mit ConsistencyLevel-HeaderWith ConsistencyLevel header |
$top$top |
Seitengröße festlegenSet page size | $top=999$top=999 |
$skip$skip |
Einträge überspringenSkip entries | $skip=100$skip=100 |
using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Kiota.Abstractions;
// Erweiterte Abfrage: endsWith benötigt ConsistencyLevel: eventual
var users = await graphClient.Users.GetAsync(config =>
{
config.QueryParameters.Filter = "endsWith(userPrincipalName, '@contoso.com')";
config.QueryParameters.Count = true;
config.QueryParameters.Select = new[] { "id", "displayName", "userPrincipalName" };
config.QueryParameters.Top = 100;
config.QueryParameters.Orderby = new[] { "displayName asc" };
config.Headers.Add("ConsistencyLevel", "eventual");
});
Console.WriteLine($"Treffer: {users?.OdataCount}");
// $search auf Benutzer (ConsistencyLevel: eventual erforderlich)
var searched = await graphClient.Users.GetAsync(config =>
{
config.QueryParameters.Search = "\"displayName:Alice\"";
config.QueryParameters.Select = new[] { "id", "displayName", "userPrincipalName" };
config.Headers.Add("ConsistencyLevel", "eventual");
});
// $expand: Gruppen-Mitglieder einbetten
var group = await graphClient.Groups["GROUP_ID"].GetAsync(config =>
{
config.QueryParameters.Select = new[] { "id", "displayName" };
config.QueryParameters.Expand = new[] { "members($select=id,displayName,userPrincipalName)" };
});
foreach (var member in group?.Members ?? new List<DirectoryObject>())
{
if (member is User u) Console.WriteLine($" Member: {u.DisplayName}");
}
// $filter mit logischen Operatoren
var guestEngineers = await graphClient.Users.GetAsync(config =>
{
config.QueryParameters.Filter =
"userType eq 'Guest' and department eq 'Engineering'";
config.QueryParameters.Select = new[] { "id", "displayName", "userPrincipalName" };
});
Batch-Anfragen (JSON Batching) Batch requests (JSON batching)
Mit JSON-Batching können bis zu 20 Graph-Anfragen in einem einzigen HTTP-Aufruf an https://graph.microsoft.com/v1.0/$batch kombiniert werden. Das reduziert die Anzahl der Roundtrips erheblich. Abhängigkeiten zwischen Teilanfragen können mit dem dependsOn-Feld gesteuert werden.
With JSON batching, up to 20 Graph requests can be combined into a single HTTP call to https://graph.microsoft.com/v1.0/$batch. This significantly reduces the number of roundtrips. Dependencies between sub-requests can be controlled with the dependsOn field.
using Microsoft.Graph;
using Microsoft.Graph.Batch;
// Batch-Anfrage mit mehreren unabhängigen Anfragen
var batchRequestContent = new BatchRequestContentCollection(graphClient);
// Anfrage 1: Benutzerinformationen
var userReq = await batchRequestContent.AddBatchRequestStepAsync(
graphClient.Users["alice@contoso.com"].ToGetRequestInformation());
// Anfrage 2: Gruppen des Benutzers
var groupsReq = await batchRequestContent.AddBatchRequestStepAsync(
graphClient.Users["alice@contoso.com"].MemberOf.ToGetRequestInformation());
// Anfrage 3: Alle globalen Admins
var adminsReq = await batchRequestContent.AddBatchRequestStepAsync(
graphClient.DirectoryRoles.ToGetRequestInformation());
// Batch ausführen
var batchResponse = await graphClient.Batch.PostAsync(batchRequestContent);
// Ergebnisse extrahieren
var user = await batchResponse.GetResponseByIdAsync<User>(userReq);
var groups = await batchResponse.GetResponseByIdAsync<DirectoryObjectCollectionResponse>(groupsReq);
Console.WriteLine($"User: {user?.DisplayName}");
Console.WriteLine($"Groups: {groups?.Value?.Count}");
// JSON-Batch direkt (für HTTP-Prototypen)
/*
POST https://graph.microsoft.com/v1.0/$batch
Content-Type: application/json
{
"requests": [
{ "id": "1", "method": "GET", "url": "/users/alice@contoso.com" },
{ "id": "2", "method": "GET", "url": "/users/alice@contoso.com/memberOf",
"dependsOn": ["1"] },
{ "id": "3", "method": "PATCH", "url": "/users/bob@contoso.com",
"body": { "department": "Finance" },
"headers": { "Content-Type": "application/json" } }
]
}
*/
Delta-Abfragen (Change Tracking) Delta queries (Change tracking)
Delta-Abfragen ermöglichen die inkrementelle Synchronisation von Graph-Ressourcen, indem nur Änderungen seit dem letzten Abruf zurückgegeben werden. Ein Delta-Token (@odata.deltaLink) wird gespeichert und bei der nächsten Anfrage übergeben. Unterstützte Ressourcen: users, groups, directoryRoles, messages, calendarView, contacts, driveItems.
Delta queries enable incremental synchronization of Graph resources by returning only changes since the last fetch. A delta token (@odata.deltaLink) is stored and passed on the next request. Supported resources: users, groups, directoryRoles, messages, calendarView, contacts, driveItems.
import asyncio, json
from pathlib import Path
from azure.identity.aio import ClientSecretCredential
from msgraph import GraphServiceClient
from msgraph.generated.users.delta.delta_request_builder import DeltaRequestBuilder
from kiota_abstractions.base_request_configuration import RequestConfiguration
DELTA_TOKEN_FILE = "delta_token.json"
async def sync_users(client: GraphServiceClient):
"""Inkrementelle Benutzersynchronisation mit Delta-Token."""
# Delta-Token laden oder erstmaligen Sync starten
delta_token = None
if Path(DELTA_TOKEN_FILE).exists():
with open(DELTA_TOKEN_FILE) as f:
delta_token = json.load(f).get("token")
all_changes = []
if delta_token:
# Inkrementeller Abruf: nur Änderungen seit letztem Sync
url = f"https://graph.microsoft.com/v1.0/users/delta?$deltaToken={delta_token}"
response = await client.users.delta.with_url(url).get()
else:
# Erster Sync: alle Benutzer + initialen Delta-Token erhalten
query_params = DeltaRequestBuilder.DeltaRequestBuilderGetQueryParameters(
select=["id", "displayName", "userPrincipalName", "department", "accountEnabled"]
)
config = RequestConfiguration(query_parameters=query_params)
response = await client.users.delta.get(request_configuration=config)
# Seiten durchlaufen
while response:
for user in response.value:
if hasattr(user, "additional_data") and "@removed" in user.additional_data:
print(f"GELÖSCHT: {user.id}")
else:
print(f"GEÄNDERT/NEU: {user.display_name} ({user.user_principal_name})")
all_changes.append(user)
if response.odata_next_link:
response = await client.users.delta.with_url(response.odata_next_link).get()
elif response.odata_delta_link:
# Delta-Token für nächsten Sync speichern
token = response.odata_delta_link.split("$deltaToken=")[-1]
with open(DELTA_TOKEN_FILE, "w") as f:
json.dump({"token": token}, f)
break
else:
break
return all_changes
async def main():
cred = ClientSecretCredential("TENANT_ID", "CLIENT_ID", "CLIENT_SECRET")
client = GraphServiceClient(credentials=cred,
scopes=["https://graph.microsoft.com/.default"])
changes = await sync_users(client)
print(f"Änderungen verarbeitet: {len(changes)}")
await cred.close()
asyncio.run(main())
Webhooks & Change Notifications Webhooks & change notifications
Change Notifications (Webhooks) ermöglichen es, Echtzeitbenachrichtigungen über Ressourcenänderungen zu empfangen. Ein Subscription-Objekt wird erstellt, das eine HTTPS-Endpunkt-URL enthält. Graph sendet eine Validierungsanfrage bei der Erstellung und danach Benachrichtigungen bei Änderungen. Subscriptions müssen regelmäßig erneuert werden (maximale Lebenszeit je nach Ressource 1 Stunde bis 4230 Minuten). Change notifications (webhooks) allow receiving real-time notifications about resource changes. A subscription object is created containing an HTTPS endpoint URL. Graph sends a validation request during creation and then notifications on changes. Subscriptions must be regularly renewed (maximum lifetime depending on resource from 1 hour to 4230 minutes).
using Microsoft.Graph.Models;
// Subscription für Benutzeränderungen erstellen
var subscription = new Subscription
{
ChangeType = "created,updated,deleted",
NotificationUrl = "https://webhook.contoso.com/api/graph/notify",
Resource = "/users",
ExpirationDateTime = DateTimeOffset.UtcNow.AddMinutes(4230),
ClientState = "SecretClientState-" + Guid.NewGuid(),
// Rich Notifications (Ressourcendaten in Payload einbetten)
IncludeResourceData = true,
EncryptionCertificate = Convert.ToBase64String(
certBytes), // Öffentliches Zertifikat
EncryptionCertificateId = "MyCertId"
};
var createdSub = await graphClient.Subscriptions.PostAsync(subscription);
Console.WriteLine($"Subscription Id: {createdSub?.Id}, läuft ab: {createdSub?.ExpirationDateTime}");
// Subscription erneuern (vor Ablauf aufrufen)
var renewal = new Subscription
{
ExpirationDateTime = DateTimeOffset.UtcNow.AddMinutes(4230)
};
await graphClient.Subscriptions[createdSub!.Id].PatchAsync(renewal);
// Subscription löschen
await graphClient.Subscriptions[createdSub.Id].DeleteAsync();
// Webhook-Empfänger (Azure Function / ASP.NET Controller) – Validierung
/*
[HttpPost("notify")]
public async Task<IActionResult> Notify()
{
// Validierungsanfrage bei Subscription-Erstellung
if (Request.Query.ContainsKey("validationToken"))
return Content(Request.Query["validationToken"], "text/plain");
var body = await new StreamReader(Request.Body).ReadToEndAsync();
var notifications = JsonSerializer.Deserialize<ChangeNotificationCollection>(body);
foreach (var notification in notifications!.Value!)
{
// clientState prüfen!
if (notification.ClientState != expectedClientState) return Unauthorized();
// Ressourcendaten verarbeiten
_queue.Enqueue(notification.ResourceData?.Id ?? notification.Resource);
}
return Accepted();
}
*/
Pagination & Throttling Pagination & throttling
Graph gibt standardmäßig maximal 100 Objekte pro Seite zurück (einige Endpunkte bis zu 999). Das @odata.nextLink-Feld in der Antwort enthält die URL für die nächste Seite. Bei Throttling gibt Graph HTTP 429 mit einem Retry-After-Header zurück, der angibt, wie viele Sekunden gewartet werden soll.
Graph returns a maximum of 100 objects per page by default (some endpoints up to 999). The @odata.nextLink field in the response contains the URL for the next page. On throttling, Graph returns HTTP 429 with a Retry-After header indicating how many seconds to wait.
| RessourceResource | Max. $topMax. $top | Throttling-LimitThrottling limit |
|---|---|---|
| Benutzer (/users)Users (/users) | 999999 | 10.000 Req/10 min pro App10,000 req/10 min per app |
| Gruppen (/groups)Groups (/groups) | 999999 | Tenant-basiertTenant-based |
| Nachrichten (/messages)Messages (/messages) | 10001000 | 10.000 Req/10 min pro Mailbox10,000 req/10 min per mailbox |
| Drive ItemsDrive items | 200200 | Tenant-basiertTenant-based |
/**
* Ruft alle Seiten einer Graph-Antwort ab.
* Verarbeitet automatisch @odata.nextLink-Pagination und 429 Throttling.
*/
async function getAllPages(client, initialRequest) {
const allItems = [];
let response = await initialRequest;
allItems.push(...(response.value || []));
while (response["@odata.nextLink"]) {
try {
response = await client.api(response["@odata.nextLink"]).get();
allItems.push(...(response.value || []));
} catch (error) {
if (error.statusCode === 429) {
const retryAfter = parseInt(error.headers?.["retry-after"] || "10", 10);
console.warn(`Throttled. Retry nach ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
// Letzte Anfrage wiederholen
response = await client.api(response["@odata.nextLink"]).get();
allItems.push(...(response.value || []));
} else {
throw error;
}
}
}
return allItems;
}
// Alle Benutzer eines Tenants (paginiert)
const allUsers = await getAllPages(
client,
client.api("/users")
.select("id,displayName,userPrincipalName")
.top(999)
.get()
);
console.log(`Gesamt: ${allUsers.length} Benutzer`);
Verwende immer exponentielles Backoff mit Jitter bei Wiederholungsversuchen. Die Graph-SDKs enthalten eine eingebaute Retry-Middleware, die 429-Antworten automatisch behandelt. Setze auf Anwendungsebene zusätzlich Rate-Limiting und verteile Last über mehrere Dienst-Principals, um Tenant-weite Limits zu vermeiden. Always use exponential backoff with jitter for retries. The Graph SDKs include built-in retry middleware that automatically handles 429 responses. Additionally implement application-level rate limiting and distribute load across multiple service principals to avoid tenant-wide limits.
Microsoft Graph Data Connect Microsoft Graph Data Connect
Graph Data Connect (MGDC) ermöglicht den Massenabruf von Microsoft 365-Daten (E-Mails, Kalender, Teams-Nachrichten, SharePoint-Metadaten, Benutzerprofile) in Azure Data Lake Storage. Im Gegensatz zur REST-API eignet sich MGDC für Analytics-, ML- und Data-Warehouse-Szenarien mit Milliarden von Ereignissen. Graph Data Connect (MGDC) enables bulk retrieval of Microsoft 365 data (emails, calendar, Teams messages, SharePoint metadata, user profiles) into Azure Data Lake Storage. Unlike the REST API, MGDC is suited for analytics, ML, and data warehouse scenarios with billions of events.
| AspektAspect | Graph REST APIGraph REST API | Graph Data ConnectGraph Data Connect |
|---|---|---|
| SkalierungScale | Tausende Objekte/AufrufThousands of objects/call | Millionen bis MilliardenMillions to billions |
| LatenzLatency | EchtzeitReal-time | Batch (Stunden)Batch (hours) |
| AusgabeOutput | JSON via HTTPJSON via HTTP | Azure Data Lake Storage Gen2Azure Data Lake Storage Gen2 |
| GenehmigungApproval | App-BerechtigungApp permission | Microsoft 365 Admin + PAM-GenehmigungMicrosoft 365 admin + PAM approval |
| DatenschutzPrivacy | Tenant-KontrolleTenant control | Scoped Access, User ExclusionScoped access, user exclusion |
| NutzungsszenarienUse cases | Betriebliche Prozesse, CRUDOperational processes, CRUD | Analyse, ML, Compliance, ReportingAnalytics, ML, compliance, reporting |
Microsoft Graph Connectors Microsoft Graph connectors
Graph Connectors ermöglichen es, externe Datenquellen (ServiceNow, Salesforce, Azure DevOps, Confluence, benutzerdefinierte Datenbanken) in den Microsoft Graph-Suchindex einzubringen. Eingebundene Inhalte erscheinen in Microsoft Search, Copilot und in der Viva Insights Experience. Graph connectors allow external data sources (ServiceNow, Salesforce, Azure DevOps, Confluence, custom databases) to be indexed into the Microsoft Graph search index. Ingested content appears in Microsoft Search, Copilot, and the Viva Insights experience.
using Microsoft.Graph.Models.ExternalConnectors;
// 1. Connector erstellen
var connector = new ExternalConnection
{
Id = "contosoproducts",
Name = "Contoso Produktkatalog",
Description = "Produkte aus dem internen ERP-System",
ActivitySettings = new ActivitySettings
{
UrlToItemResolvers = new List<UrlToItemResolverBase>
{
new ItemIdResolver
{
UrlMatchInfo = new UrlMatchInfo
{
BaseUrls = new List<string> { "https://erp.contoso.com" },
UrlPattern = "/products/(?<id>[^/]+)"
},
ItemId = "{id}"
}
}
}
};
var created = await graphClient.External.Connections.PostAsync(connector);
// 2. Schema registrieren
var schema = new Schema
{
BaseType = "microsoft.graph.externalItem",
Properties = new List<Property>
{
new() { Name = "productId", Type = PropertyType.String, IsQueryable = true, IsSearchable = false, IsRetrievable = true },
new() { Name = "title", Type = PropertyType.String, IsQueryable = true, IsSearchable = true, IsRetrievable = true },
new() { Name = "description", Type = PropertyType.String, IsQueryable = false, IsSearchable = true, IsRetrievable = true },
new() { Name = "price", Type = PropertyType.Double, IsQueryable = true, IsSearchable = false, IsRetrievable = true }
}
};
await graphClient.External.Connections["contosoproducts"].Schema.PatchAsync(schema);
// 3. Elemente einbringen
var item = new ExternalItem
{
Id = "product-001",
Properties = new Properties { AdditionalData = new Dictionary<string, object>
{
["productId"] = "P-001",
["title"] = "Widget Pro 3000",
["description"] = "Hochleistungs-Widget für industrielle Anwendungen",
["price"] = 299.99
}},
Content = new ExternalItemContent
{
Type = ExternalItemContentType.Text,
Value = "Widget Pro 3000 – Hochleistungs-Widget mit 3-Jahres-Garantie."
},
Acl = new List<Acl>
{
new() { Type = AclType.Everyone, Value = "everyone", AccessType = AccessType.Grant }
}
};
await graphClient.External.Connections["contosoproducts"]
.Items["product-001"].PutAsync(item);
Microsoft Graph Toolkit Microsoft Graph Toolkit
Das Graph Toolkit ist eine Sammlung wiederverwendbarer Web-Komponenten (Custom Elements), die Graph-Daten rendern – Benutzerkarten, Personenauswahl, Agenda, Dateibrowser und mehr. Es abstrahiert den API-Aufruf und das Token-Management und ist für Teams-Tabs, SharePoint-Webparts und eigenständige Web-Apps geeignet. The Graph Toolkit is a collection of reusable web components (Custom Elements) that render Graph data – user cards, people pickers, agendas, file browsers, and more. It abstracts API calls and token management and is suitable for Teams tabs, SharePoint web parts, and standalone web apps.
<!-- CDN-Einbindung -->
<script type="module"
src="https://unpkg.com/@microsoft/mgt@4/dist/bundle/mgt-loader.js">
</script>
<!-- MSAL2-Provider konfigurieren -->
<mgt-msal2-provider
client-id="YOUR_CLIENT_ID"
login-type="popup"
scopes="User.Read,Calendars.Read,Files.Read">
</mgt-msal2-provider>
<!-- Anmelde-Button -->
<mgt-login></mgt-login>
<!-- Aktueller Benutzer als Karte -->
<mgt-person person-query="me" view="twolines"></mgt-person>
<!-- Personen-Auswahl -->
<mgt-people-picker
type="person,group"
group-id="TEAM_GROUP_ID">
</mgt-people-picker>
<!-- Kalender-Agenda (nächste 7 Tage) -->
<mgt-agenda days="7" event-query="/me/calendarView"></mgt-agenda>
<!-- OneDrive Datei-Browser -->
<mgt-file-list></mgt-file-list>
<!-- Toolkit in SPFx / Teams (TypeScript) -->
<script type="module">
import { Providers, TeamsProvider } from "@microsoft/mgt";
import { TeamsMsal2Provider } from "@microsoft/mgt-teams-msal2-provider";
// Teams-Context-Provider
Providers.globalProvider = new TeamsMsal2Provider({
clientId: "YOUR_CLIENT_ID",
scopes: ["User.Read", "Calendars.Read"]
});
// Programmatischer Zugriff auf Graph via Toolkit-Provider
const provider = Providers.globalProvider;
const token = await provider.getAccessToken({ scopes: ["User.Read"] });
const response = await fetch("https://graph.microsoft.com/v1.0/me", {
headers: { Authorization: `Bearer ${token}` }
});
const me = await response.json();
console.log(me.displayName);
</script>
Graph Explorer Graph Explorer
Graph Explorer (developer.microsoft.com/graph/graph-explorer) ist ein browserbasiertes Tool zum Erkunden und Testen von Graph-API-Anfragen ohne eigene App-Registrierung. Es bietet Beispielabfragen, Token-Inspektion, Berechtigung-Konsentierung und direkten API-Zugriff mit dem eigenen Entra-Konto.
Graph Explorer (developer.microsoft.com/graph/graph-explorer) is a browser-based tool for exploring and testing Graph API requests without your own app registration. It provides sample queries, token inspection, permission consent, and direct API access with your own Entra account.
Verwende den Tab Request Headers, um ConsistencyLevel: eventual für erweiterte Abfragen hinzuzufügen. Unter Modify permissions kannst du fehlende Berechtigungen direkt konsentieren. Der Code snippets-Tab generiert SDK-Codebeispiele in C#, JS, Python, Java, Go und PHP – ideal zum Einstieg in neue Abfragetypen.
Use the Request Headers tab to add ConsistencyLevel: eventual for advanced queries. Under Modify permissions you can consent missing permissions directly. The Code snippets tab generates SDK code examples in C#, JS, Python, Java, Go, and PHP – ideal for getting started with new query types.
Das PowerShell-SDK bietet für jeden Graph-Endpunkt generierte Cmdlets nach dem Verb-Noun-Muster: Get-MgUser, New-MgGroup, Invoke-MgGraphRequest. Letzteres ist besonders nützlich für Endpunkte ohne spezifisches Cmdlet oder für Batch-Anfragen direkt aus PowerShell.
The PowerShell SDK provides generated cmdlets for every Graph endpoint following the Verb-Noun pattern: Get-MgUser, New-MgGroup, Invoke-MgGraphRequest. The latter is particularly useful for endpoints without a specific cmdlet or for batch requests directly from PowerShell.
Install-Module Microsoft.Graph -Scope CurrentUser -Force
# App-only Authentifizierung mit Client Credentials
Connect-MgGraph -TenantId $tenantId -ClientId $appId -ClientSecretCredential `
(New-Object System.Management.Automation.PSCredential($appId,
(ConvertTo-SecureString $secret -AsPlainText -Force)))
# Alternativ: Zertifikat
Connect-MgGraph -TenantId $tenantId -ClientId $appId -CertificateThumbprint $thumbprint
# Benutzer mit ConsistencyLevel-Header und $count abrufen
$users = Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/users?`$count=true&`$top=999&`$select=id,displayName,userPrincipalName" `
-Headers @{ "ConsistencyLevel" = "eventual" }
Write-Host "Gesamt: $($users.'@odata.count') Benutzer"
# Batch-Anfrage über Invoke-MgGraphRequest
$batchBody = @{
requests = @(
@{ id = "1"; method = "GET"; url = "/users/alice@contoso.com" },
@{ id = "2"; method = "GET"; url = "/users/bob@contoso.com" }
)
} | ConvertTo-Json -Depth 5
$batchResponse = Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/`$batch" `
-Body $batchBody -ContentType "application/json"
$batchResponse.responses | ForEach-Object {
Write-Host "Id: $($_.id), Status: $($_.status), Name: $($_.body.displayName)"
}
# Delta für Gruppen
$deltaResponse = Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/groups/delta?`$select=displayName,members"
# Delta-Token extrahieren und speichern
$deltaLink = $deltaResponse.'@odata.deltaLink'
Write-Host "Delta-Token gespeichert: $($deltaLink.Length) Zeichen"
Disconnect-MgGraph