4 minute read

This is a guide to help you avoid using client secrets in Azure when authenticating with EntraID (Azure AD) and Microsoft Identity Web.

Intro

A common pattern when hosting an application in Azure using EntraID is to have an AppRegistration containing the application’s authorization setup. The app usually connects to some downstream APIs and this requires the host service to have an identification. This is often done with a ClientId and a ClientSecret combination.

The ClientSecret is a generated string, and should be both rotated frequently and also creates a risk of exposure in appsettings and env variables.

There exists a way to avoid ClientSecrets entirely, using Federated Credentials!

What are federated credentials?

Federated credentials is a way to add permissions directly to a specified “Identity”. So instead of handing out a secret “key” we ask the identity to identify itself and then give the correct permissions. This helps us completely avoid any secrets, expiration etc!

Prerequisites

This guide assumes you have an:

  • ASP.NET API service setup with the Microsoft.Identity.Web package for Authentication and Authorization.
  • App hosted in Azure, the guide assumes using an AppService but other hosting options should work as well.
  • App Registration in Azure AD for your API

Setting up federated credentials

  1. Create a User Assigned Managed Identity in Azure. This will be the identity of your app when it connects to downstream APIs.
    1. Go to the Azure Portal, navigate to “Managed Identities” and create a new User Assigned Managed Identity.
      1. I suggest having a naming convention for your identities, for example: id-[app-name] to easily identify them later.
      2. Place them in the same region as your app.
    2. Note down the ClientId of the Managed Identity, you will need it later.
  2. Go to your App Registration in Azure AD and navigate to “Certificates & secrets” -> “Federated credentials” and add a new credential.
    1. Select “User Assigned Managed Identity” as the credential type.
    2. Select the subscription and the Managed Identity you created in step 1.
    3. For the “Subject identifier” field, use the ClientId of the Managed Identity (from step 1.2).
    4. The Name field is just a friendly name for you to identify the credential. cred-id-[app-name] is a good naming convention.
    5. Save the credential.
  3. Then in the AppService hosting your app, go to “Identity” and add the User Assigned Managed Identity you created in step 1.
  4. In the Environment Variables of your AppService, add the following variables:
    1. AzureAd__ClientId with the value of the ClientId of your App Registration (not the Managed Identity).
    2. AzureAd__TenantId with the value of your TenantId.
    3. AzureAd__ClientCredentials__0__SourceType = SignedAssertionFromManagedIdentity
    4. AzureAd__ClientCredentials__0__ManagedIdentityClientId = ClientId of the Managed Identity (from step 1.2) (⚠️ NOT the App Registration’s ClientId).
    5. Remove any existing ClientSecret configuration if you have it, usually AzureAd__ClientSecret or similar.
    6. Apply the changes (restart the app if needed).
  5. Your app should now use the federated credential to authenticate with EntraID without any client secrets!

Fin

There are more docs on this process in the Microsoft docs. My most important learning was that using the SYSTEM Assigned Credential did not work as they do not get assigned a ClientId, so we cannot use them for the ManagedIdentityClientId configuration. Also the AzureAd__ClientCredentials__0__SourceType, the __0__ is used to place the item as an object in array position 0 of the ClientCredentials JSON array. If you use the appsettings.json file instead of environment variables, it would look like this:

"AzureAd": {
  "ClientId": "your-app-registration-client-id",
  "TenantId": "your-tenant-id",
  "ClientCredentials": [
    {
      "SourceType": "SignedAssertionFromManagedIdentity",
      "ManagedIdentityClientId": "your-managed-identity-client-id"
    }
  ]
}

I hope this guide lets you avoid storing secrets for this! No more expired or leaked secrets! 🔐

End

// Nils Henrik // Human written, AI reviewed