Quickstart: Acquire a token and call Microsoft Graph in a .NET Core console app

The following quickstart uses a code sample to demonstrates how a .NET Core console application can get an access token to call the Microsoft Graph API and display a list of users in the directory. It also demonstrates how a job or a Windows service can run with an application identity, instead of a user's identity. The sample console application in this quickstart is also a daemon application, therefore it's a confidential client application.

The following diagram shows how the sample app works:

Diagram that shows how the sample app generated by this quickstart works.

Prerequisites

This quickstart requires .NET Core 6.0 SDK.

Register and download the app

The application can be built using either an automatic or manual configuration.

Automatic configuration

To register and automatically configure the app and then download the code sample, follow these steps:

  1. Sign in to the Microsoft Entra admin center as at least a Cloud Application Administrator.
  2. If you have access to multiple tenants, use the Settings icon in the top menu to switch to the tenant in which you want to register the application from the Directories + subscriptions menu.
  3. Browse to Identity > Applications > App registrations and select New registration.
  4. Enter a name for your application and select Register.
  5. Follow the instructions to download and automatically configure your new application in one click.

Manual configuration

To manually configure your application and code sample, use the following procedures.

Step 1: Register your application

Tip

Steps in this article may vary slightly based on the portal you start from.

To register the application and add the registration information to the solution manually, follow these steps:

  1. Sign in to the Microsoft Entra admin center as at least a Cloud Application Administrator.
  2. If you have access to multiple tenants, use the Settings icon in the top menu to switch to the tenant in which you want to register the application from the Directories + subscriptions menu.
  3. Browse to Identity > Applications > App registrations and select New registration.
  4. For Name, enter a name for the application. For example, enter Daemon-console. Users of the app will see this name, and can be changed later.
  5. Select Register to create the application.
  6. Under Manage, select Certificates & secrets.
  7. Under Client secrets, select New client secret, enter a name, and then select Add. Record the secret value in a safe location for use in a later step.
  8. Under Manage, select API Permissions > Add a permission. Select Microsoft Graph.
  9. Select Application permissions.
  10. Under the User node, select User.Read.All, and then select Add permissions.

Step 2: Download your Visual Studio project

Download the Visual Studio project

This project can be run in either Visual Studio or Visual Studio for Mac and can be downloaded from the code sample.

Tip

To avoid errors caused by path length limitations in Windows, we recommend extracting the archive or cloning the repository into a directory near the root of your drive.

Step 3: Configure your Visual Studio project

  1. Extract the .zip file to a local folder that's close to the root of the disk to avoid errors caused by path length limitations on Windows. For example, extract to C:\Azure-Samples.

  2. Open the solution in Visual Studio: 1-Call-MSGraph\daemon-console.sln (optional).

  3. In appsettings.json, replace the values of Tenant, ClientId, and ClientSecret. The value for the application (client) ID and the directory (tenant) ID, can be found in the app's Overview page on the Microsoft Entra admin center.

    "TenantId": "Enter_the_Tenant_Id_Here",
    "ClientId": "Enter_the_Application_Id_Here",
    "ClientSecret": "Enter_the_Client_Secret_Here"
    

    In the code:

    • Enter_the_Application_Id_Here is the application (client) ID for the registered application.
    • Replace Enter_the_Tenant_Id_Here with the tenant ID or tenant name (for example, contoso.microsoft.com).
    • Replace Enter_the_Client_Secret_Here with the client secret that you created in step 1. To generate a new key, go to the Certificates & secrets page.

Running the application now results in the output HTTP 403 - Forbidden* error: "Insufficient privileges to complete the operation. This error occurs because any app-only permission requires a global administrator of the directory to give consent to the application. Select one of the following options, depending on the role.

Global tenant administrator

For a global tenant administrator, go to Enterprise applications in the Microsoft Entra admin center. Select the app registration, and select Permissions from the Security section of the left pane. Then select the large button labeled Grant admin consent for {Tenant Name} (where {Tenant Name} is the name of the directory).

Standard user

For a standard user of your tenant, ask a global administrator to grant admin consent to the application. To do this, provide the following URL to the administrator:

https://login.microsoftonline.com/Enter_the_Tenant_Id_Here/adminconsent?client_id=Enter_the_Application_Id_Here

In the URL:

  • Replace Enter_the_Tenant_Id_Here with the tenant ID or tenant name (for example, contoso.microsoft.com).
  • Enter_the_Application_Id_Here is the application (client) ID for the registered application.

The error AADSTS50011: No reply address is registered for the application may be displayed after you grant consent to the app by using the preceding URL. This error occurs because the application and the URL don't have a redirect URI. This can be ignored.

Step 5: Run the application

In Visual Studio, press F5 to run the application. Otherwise, run the application via command prompt, console, or terminal:

cd {ProjectFolder}\1-Call-MSGraph\daemon-console
dotnet run

In that code:

  • {ProjectFolder} is the folder where you extracted the .zip file. An example is C:\Azure-Samples\active-directory-dotnetcore-daemon-v2.

The number of users in Microsoft Entra ID should be displayed as a result.

This quickstart application uses a client secret to identify itself as a confidential client. The client secret is added as a plain-text file to the project files. For security reasons, it's recommended to use a certificate instead of a client secret before considering the application as a production application. For more information on how to use a certificate, see these instructions.

More information

This section provides an overview of the code required to sign in users. The overview can be useful to understand how the code works, what the main arguments are, and how to add sign-in to an existing .NET Core console application.

Microsoft.Identity.Web.GraphServiceClient

Microsoft Identity Web (in the Microsoft.Identity.Web.TokenAcquisition package) is the library that's used to request tokens for accessing an API protected by the Microsoft identity platform. This quickstart requests tokens by using the application's own identity instead of delegated permissions. The authentication flow in this case is known as a client credentials OAuth flow. For more information on how to use MSAL.NET with a client credentials flow, see this article. Given the daemon app in this quickstart calls Microsoft Graph, you install the Microsoft.Identity.Web.GraphServiceClient package, which handles automatically authenticated requests to Microsoft Graph (and references itself Microsoft.Identity.Web.TokenAcquisition)

Microsoft.Identity.Web.GraphServiceClient can be installed by running the following command in the Visual Studio Package Manager Console:

dotnet add package Microsoft.Identity.Web.GraphServiceClient

Application initialization

Add the reference for Microsoft.Identity.Web by adding the following code:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

Then, initialize the app with the following code:

// Get the Token acquirer factory instance. By default it reads an appsettings.json
// file if it exists in the same folder as the app (make sure that the 
// "Copy to Output Directory" property of the appsettings.json file is "Copy if newer").
TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();

// Configure the application options to be read from the configuration
// and add the services you need (Graph, token cache)
IServiceCollection services = tokenAcquirerFactory.Services;
services.AddMicrosoftGraph();
// By default, you get an in-memory token cache.
// For more token cache serialization options, see https://aka.ms/msal-net-token-cache-serialization

// Resolve the dependency injection.
var serviceProvider = tokenAcquirerFactory.Build();

This code uses the configuration defined in the appsettings.json file:

{
  "AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "TenantId": "[Enter here the tenantID or domain name for your Azure AD tenant]",
  "ClientId": "[Enter here the ClientId for your application]",
  "ClientCredentials": [
  {
    "SourceType": "ClientSecret",
    "ClientSecret": "[Enter here a client secret for your application]"
  }
 ]
}
}
Element Description
ClientSecret The client secret created for the application in the Microsoft Entra admin center.
ClientId The application (client) ID for the application registered in the Microsoft Entra admin center. This value can be found on the app's Overview page in the Microsoft Entra admin center.
Instance (Optional) The security token service (STS) could instance endpoint for the app to authenticate. It's usually https://login.microsoftonline.com/ for the public cloud.
TenantId Name of the tenant or the tenant ID.

For more information, see the reference documentation for ConfidentialClientApplication.

Calling Microsoft Graph

To request a token by using the app's identity, use the AcquireTokenForClient method:

GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>();
var users = await graphServiceClient.Users
              .GetAsync(r => r.Options.WithAppOnly());

Help and support

If you need help, want to report an issue, or want to learn about your support options, see Help and support for developers.

Next steps

To learn more about daemon applications, see the scenario overview: