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.

7 7
Offizielle SDKs Official SDKs
v1.0 v1.0
Produktions-Endpunkt Production endpoint
OData OData
Abfragesprache Query language
MSAL MSAL
Auth-Bibliothek Auth library
💡 Immer Graph SDK statt direkter HTTP-Aufrufe verwenden 💡 Always use Graph SDK instead of raw HTTP calls

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.

SDKs SDKs

.NET, JS, Java, Python, Go, PHP, PowerShell .NET, JS, Java, Python, Go, PHP, PowerShell

Auth-Muster Auth patterns

Delegiert, App-only, OBO, Client Credentials Delegated, app-only, OBO, client credentials

Erweiterte Abfragen Advanced queries

$filter, $search, ConsistencyLevel, OData $filter, $search, ConsistencyLevel, OData

Batch-Anfragen Batch requests

JSON-Batching, bis zu 20 Anfragen JSON batching, up to 20 requests

Delta-Abfragen Delta queries

Inkrementelle Änderungsverfolgung Incremental change tracking

Webhooks Webhooks

Change Notifications, Rich Notifications Change notifications, rich notifications

Pagination & Throttling Pagination & throttling

@odata.nextLink, Retry-After @odata.nextLink, Retry-After

Toolkit & Data Connect Toolkit & Data Connect

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.

C# – Installation C# – Installation
# Pakete installieren (.NET CLI)
dotnet add package Microsoft.Graph
dotnet add package Azure.Identity
C# – Client initialisieren & Benutzer abfragen C# – Initialize client & query users
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.

JavaScript – Installation JavaScript – Installation
# 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
JavaScript – Client & Abfragen JavaScript – Client & queries
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.

Python – Installation Python – Installation
pip install msgraph-sdk azure-identity
Python – Client & erweiterte Abfragen Python – Client & advanced queries
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)
C# – Managed Identity & Client Credentials C# – Managed identity & client credentials
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
C# – Erweiterte Filter mit ConsistencyLevel C# – Advanced filters with ConsistencyLevel
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.

C# – Batch-Anfragen C# – Batch requests
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.

Python – Delta-Abfrage für Benutzer Python – Delta query for users
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).

C# – Subscription erstellen & verwalten C# – Create & manage subscriptions
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
JavaScript – Vollständige Pagination mit Retry JavaScript – Complete pagination with retry
/**
 * 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`);
⚠️ Throttling-Toleranz für Produktions-Apps einplanen ⚠️ Plan throttling tolerance for production apps

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.

C# – Benutzerdefinierter Graph Connector C# – Custom Graph connector
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.

HTML / JavaScript – Graph Toolkit HTML / JavaScript – Graph Toolkit
<!-- 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.

💡 Graph Explorer Tipps für Entwickler 💡 Graph Explorer tips for developers

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.

ℹ️ PowerShell Graph SDK – schneller Einstieg ℹ️ PowerShell Graph SDK – quick start

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.

PowerShell – Graph SDK Beispiele PowerShell – Graph SDK examples
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