| topic | sample | |||
|---|---|---|---|---|
| languages |
|
|||
| products |
|
|||
| description | Shows how a daemon console app uses a managed identity to get an access token and call a downstream API using the Microsoft.Identity.Web library. |
This sample application shows how to use the Microsoft identity platform to access the data of protected API in a non-interactive process. It uses Managed Identity to acquire an Access Token(s), which is then used to call the Microsoft Graph API and access organizational data.
The app is a .NET Core console application that gets the list of "ToDos" from TodoList-WebApi project by using Microsoft Authentication Library for .NET (MSAL.NET) to acquire an access token for TodoList-WebApi.
The console application:
- acquires an access token from Microsoft Entra ID by authenticating as a managed indentity
- and then calls the Web API
TodoList-WebApiprotected using Microsoft.Identity.Web to get the a list of ToDo's, and displays the result
To run this sample, you'll need:
- Visual Studio and the .NET Core SDK
- An Internet connection
- A Windows machine (necessary if you want to run the app on Windows)
- An OS X machine (necessary if you want to run the app on Mac)
- A Linux machine (necessary if you want to run the app on Linux)
- a Microsoft Entra tenant. For more information on how to get a Microsoft Entra tenant, see How to get a Microsoft Entra tenant
- An Azure virtual machine (VM) or an app service with a configured managed identity. For information on how to set up a VM with a managed identity, follow the instructions in the managed identity article.
From your shell or command line:
git clone https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2.gitor download and extract the repository .zip file.
Given that the name of the sample is pretty long, and so are the name of the referenced NuGet packages, you might want to clone it in a folder close to the root of your hard drive, to avoid file size limitations on Windows.
Navigate to the "6-Call-OwnApi - ManagedIdentity" folder
cd "6-Call-OwnApi - ManagedIdentity"There is one project in this sample. To register it, you can:
- either follow the steps Step 2: Register the sample with your Microsoft Entra tenant and Step 3: Configure the sample to use your Microsoft Entra tenant
- or use PowerShell scripts that:
- automatically creates the Microsoft Entra applications and related objects (passwords, permissions, dependencies) for you
- modify the Visual Studio projects' configuration files.
If you want to use this automation:
-
On Windows run PowerShell and navigate to the root of the cloned directory
-
In PowerShell run:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
-
Run the script to create your Microsoft Entra application and configure the code of the sample application accordingly.
.\AppCreationScripts\Configure.ps1
Other ways of running the scripts are described in App Creation Scripts
-
Open the Visual Studio solution and click start
If you don't want to use this automation, follow the steps below
As a first step you'll need to:
- Sign in to the Microsoft Entra admin center using either a work or school account or a personal Microsoft account.
- If your account is present in more than one Microsoft Entra tenant, select
Directory + Subscriptionat the top right corner in the menu on top of the page, and switch your portal session to the desired Microsoft Entra tenant. - In the left-hand navigation pane, select the Microsoft Entra ID service, and then select App registrations.
- Navigate to the Microsoft identity platform for developers App registrations page.
- Select New registration.
- When the Register an application page appears, enter your application's registration information:
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
TodoList-webapi-daemon-v2. - Leave Supported account types on the default setting of Accounts in this organizational directory only.
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
- Select Register to create the application.
- On the app Overview page, find the Application (client) ID value and record it for later. You'll need it to configure the Visual Studio configuration file for this project.
- Select the Expose an API section:
- Use the 'Set' button to generate the default AppID URI in the form of
api://<web api client id>
If your tenant went through domain verification and you have verified domains available, you can use an AppID URI in the form of
https://<yourdomain>orhttps://<yourdomain>/<myAPI name>as well.- Click Save
- Use the 'Set' button to generate the default AppID URI in the form of
- Select the Manifest section, and:
- Edit the manifest by locating the
appRoles. The role definition is provided in the JSON code block below. Leave theallowedMemberTypesto Application only. Each role definition in this manifest must have a different valid Guid for the "id" property. - Save the manifest.
- Edit the manifest by locating the
The content of appRoles should be the following (the id can be any unique Guid)
{
...
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Daemon apps in this role can consume the web api.",
"displayName": "DaemonAppRole",
"id": "7489c77e-0f34-4fe9-bf84-0ce8b74a03c4",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "DaemonAppRole"
}
],
...
}- Assign a managed identity to the VM or app service that will run your daemon app. For instance see Assign a user-assigned managed identity to an existing VM
- Grant access for the managed identity to your web API. See Grant access to Microsoft Graph
but in the PowerShell script, replace
$serverApplicationName = "Microsoft Graph"by$serverApplicationName = "TodoList-webapi-daemon-v2"and replace the scopes by the app roles you created in the app registration for the service.
In the steps below, "ClientID" is the same as "Application ID" or "AppId".
Open the solution in Visual Studio to configure the projects
Note: if you used the setup scripts, the changes below will have been applied for you
- Open the
TodoList-WebApi\appsettings.jsonfile - Find the app key
Domainand replace the existing value with your Microsoft Entra tenant name. - Find the app key
TenantIdand replace the existing value with your Microsoft Entra tenant ID. - Find the app key
ClientIdand replace the existing value with the application ID (clientId) of theTodoList-webapi-daemon-v2application copied from the Microsoft Entra admin center.
- Open the
Daemon-Console\appsettings.jsonfile - Replace
"user-assigned-managed-identity-client-id"by the ClientId of the managed identity
In the console run the API first
cd TodoList-WebApi
dotnet runIn a separate console, start the client app
cd daemon-console
dotnet runOnce the client app is started, it will display the ToDos from the API.
The relevant code for this sample is in the Program.cs file:
-
Configure your application
Important note: even if we are building a console application, since it is a daemon, and therefore a confidential client application, as it does not access the Web APIs on behalf of a user, but on its own (application).
using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Web; using System.Collections.Generic; using System; using System.Linq; using TodoList_WebApi.Models; using Microsoft.Extensions.Logging;
// 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"). var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
// Add console logging or other services if you wish tokenAcquirerFactory.Services.AddLogging( (loggingBuilder) => loggingBuilder.SetMinimumLevel(LogLevel.Warning) .AddConsole() );
// Create a downstream API service named 'MyApi' which comes loaded with several // utility methods to make HTTP calls to the DownstreamApi configurations found // in the "MyWebApi" section of your appsettings.json file. tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", tokenAcquirerFactory.Configuration.GetSection("MyWebApi")); var sp = tokenAcquirerFactory.Build();
Here is an example of configuration (appsettings.json file)
```json
{
"MyWebApi": {
"BaseUrl": "https://localhost:44372/",
"RelativePath": "api/TodoList",
"RequestAppToken": true,
"Scopes": [ "api://web-api-application-guid/.default" ],
"AcquireTokenOptions": {
"ManagedIdentity ": {
"UserAssignedClientId ": "user-assigned-managed-identity-client-id"
}
}
}
}
-
Call your to-do list API
The
MyApidownstream API service comes preloaded with various utility methods to make HTTP calls like GET and POST and will also handle serialization and deserialization of data like JSON for you. Each call will automatically retrieve an access token from Azure which will then be cached and re-used in later calls against your protected API.You can read more about the
IDownstreamApihere.// Extract the downstream API service from the 'tokenAcquirerFactory' service provider. var api = sp.GetRequiredService<IDownstreamApi>(); // You can use the API service to make direct HTTP calls to your API. Token // acquisition is handled automatically based on the configurations in your // appsettings.json file. var result = await api.GetForAppAsync<IEnumerable<TodoItem>>("MyApi"); Console.WriteLine($"result = {result?.Count()}");
Note that:
- You don't need to define the scopes here. Applications that authenticate as themselves, using client credentials, cannot specify, in the code, the individual scopes that they want to access. The scopes (app permissions) have to be statically declared during the application registration step and are done so within the
MyWebApi:Scopessection of theappsettings.jsonfile.
- You don't need to define the scopes here. Applications that authenticate as themselves, using client credentials, cannot specify, in the code, the individual scopes that they want to access. The scopes (app permissions) have to be statically declared during the application registration step and are done so within the
The relevant code for the Web API is in the Startup.cs class. We are using the method AddMicrosoftWebApi to configure the Web API to authenticate using bearer tokens, validate them and protect the API from non authorized calls. These are the steps:
-
Configuring the API to authenticate using bearer tokens
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(Configuration);
-
Protecting the Web API
Only apps that have added the application role created on Microsoft Entra admin center for the
TodoList-webapi-daemon-v2, will contain the claimroleson their tokens. This is also taken care by Microsoft Identity WebThe protection can also be done on the
Controllerlevel, using theAuthorizeattribute andPolicy. Read more about policy based authorization:[HttpGet] [Authorize(Policy = "DaemonAppRole")] public IActionResult Get() { ... }
If you get an error when calling the API Insufficient privileges to complete the operation., this is because the tenant administrator has not granted permissions
to the application. See step 6 of Register the client app (daemon-console-v2) above.
You will typically see, on the output window, something like the following:
Failed to call the Web Api: Forbidden
Content: {
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "<a guid>",
"date": "<date>"
}
}
}Build and run your project. You have the same output, but this time, your application is authenticated with Microsoft Entra ID with the certificate instead of the application secret.
Use Stack Overflow to get support from the community.
Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before.
Make sure that your questions or comments are tagged with [msal dotnet].
If you find a bug in the sample, please raise the issue on GitHub Issues.
If you find a bug in Msal.Net, please raise the issue on MSAL.NET GitHub Issues.
To provide a recommendation, visit the following User Voice page.
If you'd like to contribute to this sample, see CONTRIBUTING.MD.
This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
For more information, see MSAL.NET's conceptual documentation:
- Quickstart: Register an application with the Microsoft identity platform
- Quickstart: Configure a client application to access web APIs
- Acquiring a token for an application with client credential flows
For more information about the underlying protocol:
For a more complex multi-tenant Web app daemon application, see active-directory-dotnet-daemon-v2