Authenticate to Azure resources from .NET apps hosted on-premises

Apps hosted outside of Azure (for example on-premises or at a third-party data center) should use an application service principal to authenticate to Azure when accessing Azure resources. Application service principal objects are created using the app registration process in Azure. When an application service principal is created, a client ID and client secret will be generated for your app. The client ID, client secret, and your tenant ID are then stored in environment variables so they can be used by the Azure SDK for .NET to authenticate your app to Azure at runtime.

A different app registration should be created for each environment the app is hosted in. This allows environment specific resource permissions to be configured for each service principal and make sure an app deployed to one environment does not talk to Azure resources that are part of another environment.

1 - Register the application in Azure

An app can be registered with Azure using either the Azure portal or the Azure CLI.

Sign in to the Azure portal and follow these steps.

Instructions Screenshot
In the Azure portal:
  1. Enter app registrations in the search bar at the top of the Azure portal.
  2. Select the item labeled App registrations under the under Services heading on the menu that appears below the search bar.
A screenshot showing how to use the top search bar in the Azure portal to find and navigate to the App registrations page.
On the App registrations page, select + New registration. A screenshot showing the location of the New registration button in the App registrations page.
On the Register an application page, fill out the form as follows.
  1. Name → Enter a name for the app registration in Azure. It is recommended this name include the app name and environment (test, prod) the app registration is for.
  2. Supported account typesAccounts in this organizational directory only.
Select Register to register your app and create the application service principal.
A screenshot showing how to fill out the Register an application page by giving the app a name and specifying supported account types as accounts in this organizational directory only.
On the App registration page for your app:
  1. Application (client) ID → This is the app id the app will use to access Azure during local development. Copy this value to a temporary location in a text editor as you will need it in a future step.
  2. Directory (tenant) id → This value will also be needed by your app when it authenticates to Azure. Copy this value to a temporary location in a text editor it will also be needed it in a future step.
  3. Client credentials → You must set the client credentials for the app before your app can authenticate to Azure and use Azure services. Select Add a certificate or secret to add credentials for your app.
A screenshot of the App registration page after the app registration has been completed.  This screenshot shows the location of the application ID and tenant ID which will be needed in a future step.  It also shows the location of the link to use to add an application secret for the app.
On the Certificates & secrets page, select + New client secret. A screenshot showing the location of the link to use to create a new client secret on the certificates and secrets page.
The Add a client secret dialog will pop out from the right-hand side of the page. In this dialog:
  1. Description → Enter a value of Current.
  2. Expires → Select a value of 24 months.
Select Add to add the secret.

IMPORTANT: Set a reminder in your calendar prior to the expiration date of the secret. This way, you can add a new secret prior and update your apps prior to the expiration of this secret and avoid a service interruption in your app.
A screenshot showing the page where a new client secret is added for the application service principal created by the app registration process.
On the Certificates & secrets page, you will be shown the value of the client secret.

Copy this value to a temporary location in a text editor as you will need it in a future step.

IMPORTANT: This is the only time you will see this value. Once you leave or refresh this page, you will not be able to see this value again. You may add an additional client secret without invalidating this client secret, but you will not see this value again.
A screenshot showing the page with the generated client secret.

2 - Assign roles to the application service principal

Next, you need to determine what roles (permissions) your app needs on what resources and assign those roles to your app. Roles can be assigned a role at a resource, resource group, or subscription scope. This example will show how to assign roles for the service principal at the resource group scope since most applications group all their Azure resources into a single resource group.

Instructions Screenshot
Locate the resource group for your application by searching for the resource group name using the search box at the top of the Azure portal.

Navigate to your resource group by selecting the resource group name under the Resource Groups heading in the dialog box.
A screenshot showing how to use the top search box in the Azure portal to locate and navigate to the resource group you want to assign roles (permissions) to.
On the page for the resource group, select Access control (IAM) from the left-hand menu. A screenshot of the resource group page showing the location of the Access control (IAM) menu item.
On the Access control (IAM) page:
  1. Select the Role assignments tab.
  2. Select + Add from the top menu and then Add role assignment from the resulting drop-down menu.
A screenshot showing how to navigate to the role assignments tab and the location of the button used to add role assignments to a resource group.
The Add role assignment page lists all of the roles that can be assigned for the resource group.
  1. Use the search box to filter the list to a more manageable size. This example shows how to filter for Storage Blob roles.
  2. Select the role that you want to assign.
Select Next to go to the next screen.
A screenshot showing how to filter and select role assignments to be added to the resource group.
The next Add role assignment page allows you to specify what user to assign the role to.
  1. Select User, group, or service principal under Assign access to.
  2. Select + Select members under Members
A dialog box will open on the right-hand side of the Azure portal.
A screenshot showing the radio button to select to assign a role to an Azure AD group and the link used to select the group to assign the role to.
In the Select members dialog:
  1. The Select text box can be used to filter the list of users and groups in your subscription. If needed, type the first few characters of the service principal you created for the app to filter the list.
  2. Select the service principal associated with your application.
Select Select at the bottom of the dialog to continue.
A screenshot showing how to filter for and select the Azure AD group for the application in the Select members dialog box.
The service principal will now show as selected on the Add role assignment screen.

Select Review + assign to go to the final page and then Review + assign again to complete the process.
A screenshot showing the completed Add role assignment page and the location of the Review + assign button used to complete the process.

3 - Configure environment variables for application

The DefaultAzureCredential object will look for service principal credentials in a set of environment variables at runtime. There are multiple ways to configure environment variables when working with .NET depending on your tooling and environment.

Regardless of which approach you choose, you will need to configure the following environment variables when working with a service principal.

  • AZURE_CLIENT_ID → The app ID value.
  • AZURE_TENANT_ID → The tenant ID value.
  • AZURE_CLIENT_SECRET → The password/credential generated for the app.

If your app is hosted in IIS it is recommended that you set environment variables per app pool to isolate settings between applications.

appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='ASPNETCORE_ENVIRONMENT',value='Production']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='AZURE_CLIENT_ID',value='00000000-0000-0000-0000-000000000000']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='AZURE_TENANT_ID',value='11111111-1111-1111-1111-111111111111']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='Contoso'].environmentVariables.[name='AZURE_CLIENT_SECRET',value='=abcdefghijklmnopqrstuvwxyz']" /commit:apphost

You can also configure these settings directly using the applicationPools element inside of the applicationHost.config file.

<applicationPools>
   <add name="CorePool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic">
      <environmentVariables>
         <add name="ASPNETCORE_ENVIRONMENT" value="Development" />
         <add name="AZURE_CLIENT_ID" value="00000000-0000-0000-0000-000000000000" />
         <add name="AZURE_TENANT_ID" value="11111111-1111-1111-1111-111111111111" />
         <add name="AZURE_CLIENT_SECRET" value="=abcdefghijklmnopqrstuvwxyz" />
      </environmentVariables>
   </add>
</applicationPools>

4 - Implement DefaultAzureCredential in application

DefaultAzureCredential supports multiple authentication methods and determines the authentication method being used at runtime. In this way, your app can use different authentication methods in different environments without implementing environment specific code.

The order and locations in which DefaultAzureCredential looks for credentials is found at DefaultAzureCredential.

To implement DefaultAzureCredential, first add the Azure.Identity and optionally the Microsoft.Extensions.Azure packages to your application. You can do this using either the command line or the NuGet Package Manager.

Open a terminal environment of your choice in the application project directory and enter the command below.

dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.Azure

Azure services are generally accessed using corresponding client classes from the SDK. These classes and your own custom services should be registered in the Program.cs file so they can be accessed via dependency injection throughout your app. Inside of Program.cs, follow the steps below to correctly setup your service and DefaultAzureCredential.

  1. Include the Azure.Identity and Microsoft.Extensions.Azure namespaces with a using statement.
  2. Register the Azure service using relevant helper methods.
  3. Pass an instance of the DefaultAzureCredential object to the UseCredential method.

An example of this is shown in the following code segment.

using Microsoft.Extensions.Azure;
using Azure.Identity;

// Inside of Program.cs
builder.Services.AddAzureClients(x =>
{
    x.AddBlobServiceClient(new Uri("https://<account-name>.blob.core.windows.net"));
    x.UseCredential(new DefaultAzureCredential());
});

Alternatively, you can also utilize DefaultAzureCredential in your services more directly without the help of additional Azure registration methods, as seen below.

using Azure.Identity;

// Inside of Program.cs
builder.Services.AddSingleton<BlobServiceClient>(x => 
    new BlobServiceClient(
        new Uri("https://<account-name>.blob.core.windows.net"),
        new DefaultAzureCredential()));

When the above code is run on your local workstation during local development, it will look in the environment variables for an application service principal or at Visual Studio, VS Code, the Azure CLI, or Azure PowerShell for a set of developer credentials, either of which can be used to authenticate the app to Azure resources during local development.

When deployed to Azure this same code can also authenticate your app to other Azure resources. DefaultAzureCredential can retrieve environment settings and managed identity configurations to authenticate to other services automatically.