topic | languages | products | ||||
---|---|---|---|---|---|---|
sample |
|
|
This sample application shows how to use the Azure AD v2.0 endpoint to access the data of Microsoft business customers in a long-running, non-interactive process. It uses the OAuth 2 client credentials grant to acquire an access token, which can be used to call the Microsoft Graph and access organizational data
The app is a .NET Core 2.1 Console application. It gets the list of users in an Azure AD tenant by using Microsoft Authentication Library (MSAL) Preview for .NET
to acquire a token.
The console application:
- gets a token from Azure AD in its own name (without a user)
- and then calls the Microsoft Graph /users endpoint to get the list of user, which it then displays (as Json blob)
For more information on the concepts used in this sample, be sure to read the v2.0 endpoint client credentials protocol documentation.
Daemon applications can use two forms of secrets to authenticate themselves with Azure AD:
- application secrets (also named application password). This is what we've seen so far.
- certificates. This is the object of this paragraph. The first form (application secret) is treated in the next paragraphs. A variation of this sample using a certificate instead of an application password is available at the end of this article in Variation: daemon application using client credentials with certificates
To run this sample, you'll need:
- Visual Studio 2017 or just 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)
- An Azure Active Directory (Azure AD) tenant. For more information on how to get an Azure AD tenant, see How to get an Azure AD tenant
- A user account in your Azure AD tenant. This sample will not work with a Microsoft account (formerly Windows Live account). Therefore, if you signed in to the Azure portal with a Microsoft account and have never created a user account in your directory before, you need to do that now.
From your shell or command line:
git clone https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2.git
or 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.
There is one project in this sample. To register it, you can:
- either follow the steps Step 2: Register the sample with your Azure Active Directory tenant and Step 3: Configure the sample to use your Azure AD tenant
- or use PowerShell scripts that:
- automatically creates the Azure AD 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 Azure AD application and configure the code of the sample application accordinly.
.\AppCreationScripts\Configure.ps1
Other ways of running the scripts are described in App Creation Scripts
-
Open the Visual Studio solution and click start
If ou don't want to use this automation, follow the steps below
As a first step you'll need to:
- Sign in to the Azure portal using either a work or school account or a personal Microsoft account.
- If your account is present in more than one Azure AD tenant, select
Directory + Subscription
at the top right corner in the menu on top of the page, and switch your portal session to the desired Azure AD tenant. - In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations (Preview).
-
Navigate to the Microsoft identity platform for developers App registrations page.
-
Select New registration.
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
daemon-console
. - In the Supported account types section, select Accounts in this organizational directory only ({tenant name}).
- Select Register to create the application.
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
-
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.
-
From the Certificates & secrets page, in the Client secrets section, choose New client secret:
- Type a key description (of instance
app secret
), - Select a key duration of either In 1 year, In 2 years, or Never Expires.
- When you press the Add button, the key value will be displayed, copy, and save the value in a safe location.
- You'll need this key later to configure the project in Visual Studio. This key value will not be displayed again, nor retrievable by any other means, so record it as soon as it is visible from the Azure portal.
- Type a key description (of instance
-
In the list of pages for the app, select API permissions
- Click the Add a permission button and then,
- Ensure that the Microsoft APIs tab is selected
- In the Commonly used Microsoft APIs section, click on Microsoft Graph
- In the Application permissions section, ensure that the right permissions are checked: User.Read.All
- Select the Add permissions button
-
At this stage permissions are assigned correctly but the client app does not allow interaction. Therefore no consent can be presented via a UI and accepted to use the service app. Click the Grant/revoke admin consent for {tenant} button, and then select Yes when you are asked if you want to grant consent for the requested permissions for all account in the tenant. You need to be an Azure AD tenant admin to do this.
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
daemon-console\appsettings.json
file - Find the app key
Tenant
and replace the existing value with your Azure AD tenant name. - Find the app key
ClientId
and replace the existing value with the application ID (clientId) of thedaemon-console
application copied from the Azure portal. - Find the app key
ClientSecret
and replace the existing value with the key you saved during the creation of thedaemon-console
app, in the Azure portal.
Clean the solution, rebuild the solution, and run it. You might want to go into the solution properties and set both projects as startup projects, with the service project starting first.
Start the application, it will display the users in the tenant.
The relevant code for this sample is in the Program.cs
file, in the RunAsync()
method. The steps are:
-
Create the MSAL confidential client application.
Important note: even if we are building a console application, it is a daemon, and therefore a confidential client application, as it does not access Web APIs on behalf of a user, but on its own application behalf.
IConfidentialClientApplication app; app = ConfidentialClientApplicationBuilder.Create(config.ClientId) .WithClientSecret(config.ClientSecret) .WithAuthority(new Uri(config.Authority)) .Build();
-
Define the scopes.
Specific to client credentials, you don't specify, in the code, the individual scopes you want to access. You have statically declared them during the application registration step. Therefore the only possible scope is "resource/.default" (here "https://graph.microsoft.com/.default") which means "the static permissions defined in the application"
// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the // application permissions need to be set statically (in the portal or by PowerShell), and then granted by // a tenant administrator string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
-
Acquire the token
AuthenticationResult result = null; try { result = await app.AcquireTokenForClient(scopes) .ExecuteAsync(); } catch(MsalServiceException ex) { // AADSTS70011 // Invalid scope. The scope has to be of the form "https://resourceurl/.default" // Mitigation: this is a dev issue. Change the scope to be as expected }
-
Call the API
In that case calling "https://graph.microsoft.com/v1.0/users" with the access token as a bearer token.
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) 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>"
}
}
}
Daemon applications can use two forms of secrets to authenticate themselves with Azure AD:
- application secrets (also named application password). This is what we've seen so far.
- certificates. This is the object of this paragraph.
To use certificates instead of an application secret you will need to do little changes to what you have done so far:
- (optionnally) generate a certificate and export it, if you don't have one already
- register the certificate with your application in the application registration portal
- enable the sample code to use certificates instead of app secret.
If you want to use the automation script:
-
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 Azure AD application and configure the code of the sample application accordinly.
.\AppCreationScripts-WtihCert\Configure.ps1
Other ways of running the scripts are described in App Creation Scripts
-
Open the Visual Studio solution
-
Right click on the
daemon-console
project in VisualStudio and choose Properties. Then, in the Build tab, add a Conditional compilation symbol set toVariationWithCertificateCredentials
. This is to enable conditional compilation for your project to use the certificate rather than the app secret. -
Save and select start
If ou don't want to use this automation, follow the following steps:
To complete this step, you will use the New-SelfSignedCertificate
Powershell command. You can find more information about the New-SelfSignedCertificat command here.
-
Open PowerShell and run New-SelfSignedCertificate with the following parameters to create a self-signed certificate in the user certificate store on your computer:
$cert=New-SelfSignedCertificate -Subject "CN=DaemonConsoleCert" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature
-
Export this certificate using the "Manage User Certificate" MMC snap-in accessible from the Windows Control Panel. You can also add other options to generate the certificate in a different store such as the Computer or service store (See How to: View Certificates with the MMC Snap-in).
Alternatively you can use an existing certificate if you have one (just be sure to record its name for the next steps)
In the application registration blade for your application, in the Certificates & secrets page, in the Certificates section:
- Click on Upload certificate and, in click the browse button on the right to select the certificate you just exported (or your existing certificate)
- Click Add
To change the visual studio project to enable certificates you need to:
- Open the
daemon-console\appsettings.json
file - Find the app key
CertificateName
and replace the existing value with the name of your certificate (if you generated your own certificate from the instructions above, this should beCN=DaemonConsoleCert
). - Right click on the
daemon-console
project in VisualStudio and choose Properties. Then, in the Build tab, add a Conditional compilation symbol set toVariationWithCertificateCredentials
. This is to enable conditional compilation for your project to use the certificate rather than the app secret.
Build and run your project. You have the same output, but this time, your application is authenticated with Azure AD with the certificate instead of the application secret.
The code change is the following: the ClientCredentials
instance passed to the constructor of the ConfidentialClientApplication
is now built from a ClientAssertionCertificate
instance (built from the certificate) instead of from the application password
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithCertificate(certificate)
.WithAuthority(new Uri(config.Authority))
.Build();
The rest of the application is the same. The sample also has a method to retrive the certificate from the Windows certificate store (This part was not tested on linux)
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 (Preview)
- Quickstart: Configure a client application to access web APIs (Preview)
- 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