Skip to main content

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.

Overview

The Service Principals API provides operations to manage service principals (enterprise applications) in Azure AD. Access through graphClient.ServicePrincipals.

Request Builder

public ServicePrincipalsRequestBuilder ServicePrincipals { get; }
Accessed via: graphClient.ServicePrincipals

Operations

List Service Principals

Retrieve all service principals.
var servicePrincipals = await graphClient.ServicePrincipals.GetAsync();

foreach (var sp in servicePrincipals.Value)
{
    Console.WriteLine($"{sp.DisplayName}");
    Console.WriteLine($"  App ID: {sp.AppId}");
    Console.WriteLine($"  Object ID: {sp.Id}");
    Console.WriteLine($"  Type: {sp.ServicePrincipalType}");
}

// Filter service principals
var filteredSps = await graphClient.ServicePrincipals.GetAsync(config =>
{
    config.QueryParameters.Filter = "displayName eq 'Microsoft Graph'";
    config.QueryParameters.Select = new[] { "id", "appId", "displayName" };
});

Get Service Principal by ID

// By object ID
var sp = await graphClient.ServicePrincipals["object-id"].GetAsync();

// By app ID (alternate key)
var sp = await graphClient.ServicePrincipalsWithAppId("app-id").GetAsync();

Console.WriteLine($"Display Name: {sp.DisplayName}");
Console.WriteLine($"Homepage: {sp.Homepage}");

Create Service Principal

Create a service principal for an existing application.
var newSp = new ServicePrincipal
{
    AppId = "app-id-from-application",
    AccountEnabled = true,
    DisplayName = "My Service Principal",
    Tags = new[] { "WindowsAzureActiveDirectoryIntegratedApp" }
};

var sp = await graphClient.ServicePrincipals.PostAsync(newSp);
Console.WriteLine($"Created SP: {sp.Id}");

Update Service Principal

var updateSp = new ServicePrincipal
{
    AccountEnabled = false,
    Notes = "Disabled for maintenance"
};

await graphClient.ServicePrincipals["object-id"].PatchAsync(updateSp);

Delete Service Principal

await graphClient.ServicePrincipals["object-id"].DeleteAsync();

App Role Assignments

List App Role Assignments

var assignments = await graphClient.ServicePrincipals["object-id"]
    .AppRoleAssignments
    .GetAsync();

foreach (var assignment in assignments.Value)
{
    Console.WriteLine($"Principal: {assignment.PrincipalDisplayName}");
    Console.WriteLine($"Resource: {assignment.ResourceDisplayName}");
    Console.WriteLine($"Role: {assignment.AppRoleId}");
}

Assign App Role to User

var assignment = new AppRoleAssignment
{
    PrincipalId = Guid.Parse("user-id"),
    ResourceId = Guid.Parse("service-principal-id"),
    AppRoleId = Guid.Parse("role-id") // Use Guid.Empty for default access
};

await graphClient.ServicePrincipals["sp-object-id"]
    .AppRoleAssignments
    .PostAsync(assignment);

Assign App Role to Group

var groupAssignment = new AppRoleAssignment
{
    PrincipalId = Guid.Parse("group-id"),
    ResourceId = Guid.Parse("service-principal-id"),
    AppRoleId = Guid.Parse("role-id")
};

await graphClient.ServicePrincipals["sp-object-id"]
    .AppRoleAssignments
    .PostAsync(groupAssignment);

Remove App Role Assignment

await graphClient.ServicePrincipals["sp-object-id"]
    .AppRoleAssignments["assignment-id"]
    .DeleteAsync();

App Role Assigned To

List assignments where this service principal is the resource.
var assignedTo = await graphClient.ServicePrincipals["object-id"]
    .AppRoleAssignedTo
    .GetAsync();

foreach (var assignment in assignedTo.Value)
{
    Console.WriteLine($"{assignment.PrincipalDisplayName} has role {assignment.AppRoleId}");
}

OAuth2 Permission Grants

List Permission Grants

var grants = await graphClient.ServicePrincipals["object-id"]
    .Oauth2PermissionGrants
    .GetAsync();

foreach (var grant in grants.Value)
{
    Console.WriteLine($"Client: {grant.ClientId}");
    Console.WriteLine($"Resource: {grant.ResourceId}");
    Console.WriteLine($"Scope: {grant.Scope}");
    Console.WriteLine($"Type: {grant.ConsentType}");
}

Owners

List Owners

var owners = await graphClient.ServicePrincipals["object-id"].Owners.GetAsync();

foreach (var owner in owners.Value)
{
    if (owner is User user)
    {
        Console.WriteLine($"Owner: {user.DisplayName}");
    }
}

Add Owner

var ownerRef = new ReferenceCreate
{
    OdataId = $"https://graph.microsoft.com/v1.0/users/{userId}"
};

await graphClient.ServicePrincipals["object-id"].Owners.Ref.PostAsync(ownerRef);

Member Of

List groups and directory roles the service principal is a member of.
var memberOf = await graphClient.ServicePrincipals["object-id"].MemberOf.GetAsync();

foreach (var obj in memberOf.Value)
{
    if (obj is Group group)
    {
        Console.WriteLine($"Group: {group.DisplayName}");
    }
    else if (obj is DirectoryRole role)
    {
        Console.WriteLine($"Role: {role.DisplayName}");
    }
}

Delegated Permission Classifications

List Permission Classifications

var classifications = await graphClient.ServicePrincipals["object-id"]
    .DelegatedPermissionClassifications
    .GetAsync();

foreach (var classification in classifications.Value)
{
    Console.WriteLine($"{classification.PermissionName}: {classification.Classification}");
}

Create Permission Classification

var classification = new DelegatedPermissionClassification
{
    PermissionId = "permission-id",
    PermissionName = "User.Read",
    Classification = PermissionClassificationType.Low
};

await graphClient.ServicePrincipals["object-id"]
    .DelegatedPermissionClassifications
    .PostAsync(classification);

Endpoints

List Endpoints

var endpoints = await graphClient.ServicePrincipals["object-id"].Endpoints.GetAsync();

foreach (var endpoint in endpoints.Value)
{
    Console.WriteLine($"{endpoint.ProviderName}: {endpoint.Uri}");
}

Created Objects

List directory objects created by this service principal.
var createdObjects = await graphClient.ServicePrincipals["object-id"]
    .CreatedObjects
    .GetAsync();

Owned Objects

List directory objects owned by this service principal.
var ownedObjects = await graphClient.ServicePrincipals["object-id"]
    .OwnedObjects
    .GetAsync();

Certificates and Secrets

Add Password (Client Secret)

var passwordCredential = new AddPasswordPostRequestBody
{
    PasswordCredential = new PasswordCredential
    {
        DisplayName = "App Secret",
        EndDateTime = DateTime.UtcNow.AddMonths(6)
    }
};

var credential = await graphClient.ServicePrincipals["object-id"]
    .AddPassword
    .PostAsync(passwordCredential);

Console.WriteLine($"Secret: {credential.SecretText}");
// Store securely - only shown once

Remove Password

var removePassword = new RemovePasswordPostRequestBody
{
    KeyId = Guid.Parse("key-id")
};

await graphClient.ServicePrincipals["object-id"]
    .RemovePassword
    .PostAsync(removePassword);

Add Certificate

using System.Security.Cryptography.X509Certificates;

var certificate = new X509Certificate2("cert.pfx", "password");

var keyCredential = new AddKeyPostRequestBody
{
    KeyCredential = new KeyCredential
    {
        Type = "AsymmetricX509Cert",
        Usage = "Verify",
        Key = certificate.RawData,
        DisplayName = "Service Principal Certificate"
    },
    PasswordCredential = null,
    Proof = "proof-token"
};

await graphClient.ServicePrincipals["object-id"]
    .AddKey
    .PostAsync(keyCredential);

Token Signing Certificates

Add Token Signing Certificate

var tokenSigningCertificate = new AddTokenSigningCertificatePostRequestBody
{
    DisplayName = "CN=MyApp",
    EndDateTime = DateTime.UtcNow.AddYears(1)
};

var cert = await graphClient.ServicePrincipals["object-id"]
    .AddTokenSigningCertificate
    .PostAsync(tokenSigningCertificate);

Console.WriteLine($"Thumbprint: {cert.Thumbprint}");
Console.WriteLine($"Key: {cert.Key}");

Synchronization

Get Synchronization

var sync = await graphClient.ServicePrincipals["object-id"]
    .Synchronization
    .GetAsync();

List Synchronization Jobs

var jobs = await graphClient.ServicePrincipals["object-id"]
    .Synchronization
    .Jobs
    .GetAsync();

foreach (var job in jobs.Value)
{
    Console.WriteLine($"Job: {job.Id}");
    Console.WriteLine($"Status: {job.Status.State}");
}

Remote Desktop Security Configuration

Get Remote Desktop Configuration

var rdConfig = await graphClient.ServicePrincipals["object-id"]
    .RemoteDesktopSecurityConfiguration
    .GetAsync();

Common Scenarios

Find Service Principal for Application

var servicePrincipals = await graphClient.ServicePrincipals.GetAsync(config =>
{
    config.QueryParameters.Filter = $"appId eq '{applicationAppId}'";
});

var sp = servicePrincipals.Value.FirstOrDefault();
// Create OAuth2 permission grant
var grant = new OAuth2PermissionGrant
{
    ClientId = "service-principal-id",
    ConsentType = "AllPrincipals", // Admin consent
    PrincipalId = null,
    ResourceId = "resource-sp-id",
    Scope = "User.Read.All Directory.Read.All"
};

await graphClient.Oauth2PermissionGrants.PostAsync(grant);

Assign Application to User

// Assign default access
var assignment = new AppRoleAssignment
{
    PrincipalId = Guid.Parse("user-id"),
    ResourceId = Guid.Parse("sp-id"),
    AppRoleId = Guid.Empty // Default access
};

await graphClient.Users["user-id"]
    .AppRoleAssignments
    .PostAsync(assignment);

Delta Query

var delta = await graphClient.ServicePrincipals.Delta.GetAsync();

foreach (var sp in delta.Value)
{
    Console.WriteLine($"Changed: {sp.DisplayName}");
}

var deltaLink = delta.OdataDeltaLink;

Error Handling

using Microsoft.Graph.Models.ODataErrors;

try
{
    var sp = await graphClient.ServicePrincipals["object-id"].GetAsync();
}
catch (ODataError error)
{
    if (error.Error.Code == "Request_ResourceNotFound")
    {
        Console.WriteLine("Service principal not found");
    }
    else
    {
        Console.WriteLine($"Error: {error.Error.Message}");
    }
}

See Also

Service Principal Model

Service principal properties

Applications

Application registration management

OAuth2 Permission Grants

Delegated permission grants

App Roles

App role assignments