Choose a Microsoft Graph authentication provider based on the scenario

Authentication providers implement the code required to acquire a token using the Microsoft Authentication Library (MSAL), handle some potential errors for cases like incremental consent, expired passwords, and conditional access, and then set the HTTP request authorization header. The following table lists the providers that match the scenarios for different application types.

Scenario Flow/Grant Audience Provider
Single Page App Authorization Code with PKCE Delegated Consumer/Org Authorization code provider
Web App that calls web APIs
Authorization Code Delegated Consumer/Org Authorization code provider
Client Credentials App Only Client credentials provider
Web API that calls web APIs
On Behalf Of Delegated Consumer/Org On-behalf-of provider
Client Credentials App Only Client credentials provider
Desktop app that calls web APIs
Interactive Delegated Consumer/Org Interactive provider
Integrated Windows Delegated Org Integrated Windows provider
Resource Owner Delegated Org Username/password provider
Device Code Delegated Org Device code provider
Daemon app
Client Credentials App Only Client credentials provider
Mobile app that calls web APIs
Interactive Delegated Consumer/Org Interactive provider

Note

The following code snippets were written with the latest versions of their respective SDKs. If you encounter compiler errors with these snippets, make sure you have the latest versions. The following Azure Identity libraries provide the authentication providers used:

Authorization code provider

The authorization code flow enables native and web apps to obtain tokens in the user's name securely. To learn more, see Microsoft identity platform and OAuth 2.0 authorization code flow.

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";

// For authorization code flow, the user signs into the Microsoft
// identity platform, and the browser is redirected back to your app
// with an authorization code in the query parameters
var authorizationCode = "AUTH_CODE_FROM_REDIRECT";

// using Azure.Identity;
var options = new AuthorizationCodeCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

// https://learn.microsoft.com/dotnet/api/azure.identity.authorizationcodecredential
var authCodeCredential = new AuthorizationCodeCredential(
    tenantId, clientId, clientSecret, authorizationCode, options);

var graphClient = new GraphServiceClient(authCodeCredential, scopes);

Client credentials provider

The client credential flow enables service applications to run without user interaction. Access is based on the identity of the application. For more information, see Microsoft identity platform and the OAuth 2.0 client credentials flow.

Using a client certificate

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

// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var tenantId = "YOUR_TENANT_ID";
var clientCertificate = new X509Certificate2("MyCertificate.pfx");

// using Azure.Identity;
var options = new ClientCertificateCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

// https://learn.microsoft.com/dotnet/api/azure.identity.clientcertificatecredential
var clientCertCredential = new ClientCertificateCredential(
    tenantId, clientId, clientCertificate, options);

var graphClient = new GraphServiceClient(clientCertCredential, scopes);

Using a client secret

// The client credentials flow requires that you request the
// /.default scope, and pre-configure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };

// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var tenantId = "YOUR_TENANT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";

// using Azure.Identity;
var options = new ClientSecretCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
    tenantId, clientId, clientSecret, options);

var graphClient = new GraphServiceClient(clientSecretCredential, scopes);

On-behalf-of provider

The on-behalf-of flow is applicable when your application calls a service/web API, which calls the Microsoft Graph API. Learn more by reading Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow

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

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";

// using Azure.Identity;
var options = new OnBehalfOfCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

// This is the incoming token to exchange using on-behalf-of flow
var oboToken = "JWT_TOKEN_TO_EXCHANGE";

var onBehalfOfCredential = new OnBehalfOfCredential(
    tenantId, clientId, clientSecret, oboToken, options);

var graphClient = new GraphServiceClient(onBehalfOfCredential, scopes);

Implicit provider

Implicit Authentication flow isn't recommended due to its disadvantages. Public clients such as native apps and single-page apps should now use the authorization code flow with the PKCE extension instead. Reference.

Device code provider

The device code flow enables sign-in to devices through another device. For details, see Microsoft identity platform and the OAuth 2.0 device code flow.

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration
var clientId = "YOUR_CLIENT_ID";

// using Azure.Identity;
var options = new DeviceCodeCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    ClientId = clientId,
    TenantId = tenantId,
    // Callback function that receives the user prompt
    // Prompt contains the generated device code that user must
    // enter during the auth process in the browser
    DeviceCodeCallback = (code, cancellation) =>
    {
        Console.WriteLine(code.Message);
        return Task.FromResult(0);
    },
};

// https://learn.microsoft.com/dotnet/api/azure.identity.devicecodecredential
var deviceCodeCredential = new DeviceCodeCredential(options);

var graphClient = new GraphServiceClient(deviceCodeCredential, scopes);

Integrated Windows provider

The integrated Windows flow allows Windows computers to acquire an access token when domain-joined silently. For details, see Integrated Windows authentication.

The Azure.Identity package doesn't currently support Windows-integrated authentication. Instead, create a custom access token provider using MSAL.

Access token provider

public class IntegratedWindowsTokenProvider : IAccessTokenProvider
{
    private readonly IPublicClientApplication publicClient;

    /// <summary>
    /// Initializes a new instance of the <see cref="IntegratedWindowsTokenProvider"/> class.
    /// </summary>
    /// <param name="clientId">The client ID from the app registration in Azure.</param>
    /// <param name="tenantId">The tenant ID from the app registration in Azure.</param>
    public IntegratedWindowsTokenProvider(string clientId, string tenantId)
    {
        // From MSAL (Microsoft.Identity.Client)
        publicClient = PublicClientApplicationBuilder
            .Create(clientId)
            .WithTenantId(tenantId)
            .Build();

        AllowedHostsValidator = new AllowedHostsValidator();
    }

    /// <summary>
    /// Gets an <see cref="AllowedHostsValidator"/> that validates if the
    /// target host of a request is allowed for authentication.
    /// </summary>
    public AllowedHostsValidator AllowedHostsValidator { get; }

    /// <inheritdoc/>
    public async Task<string> GetAuthorizationTokenAsync(
        Uri uri,
        Dictionary<string, object>? additionalAuthenticationContext = null,
        CancellationToken cancellationToken = default)
    {
        var scopes = new[] { "User.Read" };
        var result = await publicClient
            .AcquireTokenByIntegratedWindowsAuth(scopes)
            .ExecuteAsync(cancellationToken);
        return result.AccessToken;
    }
}

Create the client

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration
var clientId = "YOUR_CLIENT_ID";

var authenticationProvider = new BaseBearerTokenAuthenticationProvider(
    new IntegratedWindowsTokenProvider(clientId, tenantId));

var graphClient = new GraphServiceClient(authenticationProvider);

return graphClient;

Interactive provider

The interactive flow is used by mobile applications (Xamarin and UWP) and desktop applications to call Microsoft Graph in the name of a user. For details, see Acquiring tokens interactively.

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration
var clientId = "YOUR_CLIENT_ID";

// using Azure.Identity;
var options = new InteractiveBrowserCredentialOptions
{
    TenantId = tenantId,
    ClientId = clientId,
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    // MUST be http://localhost or http://localhost:PORT
    // See https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/System-Browser-on-.Net-Core
    RedirectUri = new Uri("http://localhost"),
};

// https://learn.microsoft.com/dotnet/api/azure.identity.interactivebrowsercredential
var interactiveCredential = new InteractiveBrowserCredential(options);

var graphClient = new GraphServiceClient(interactiveCredential, scopes);

Username/password provider

The username/password provider allows an application to sign in a user using their username and password. Use this flow only when you can't use any other OAuth flows. For more information, see Microsoft identity platform and the OAuth 2.0 resource owner password credential

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration
var clientId = "YOUR_CLIENT_ID";

// using Azure.Identity;
var options = new UsernamePasswordCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

var userName = "adelev@contoso.com";
var password = "Password1!";

// https://learn.microsoft.com/dotnet/api/azure.identity.usernamepasswordcredential
var userNamePasswordCredential = new UsernamePasswordCredential(
    userName, password, tenantId, clientId, options);

var graphClient = new GraphServiceClient(userNamePasswordCredential, scopes);

Next steps