azurebearer-tokenazure-app-registrationdefaultazurecredential

In an Azure App Service, how do I allow DefaultAzureCredential to get bearer token from App Registration (Enterprise Application)?


I have an App Registration in Entra with permissions granted to call another App Registration from same Entra. When I use client secret to get a bearer token via http for grant_type=client_credentials - the token works fine.

Now I want to use DefaultAzureCredential inside an Azure App Service to get the same token without client secret. When I use DefaultAzureCredential.GetTokenAsync - I get a token with no Roles and oid set to the system-assigned identity of my App Service. I tried Passing DefaultAzureCredentialOptions.ManagedIdentityClientId set to Client Id of my App Registration, but then I get code 400, indicating that my App Service does not have permissions to use the identity from App Registration.

Am I missing some configuration to link my App Service to my App Registration?

Update I've recreated the setup, here is what it looks like:

App Registrations:

enter image description here

Http call gets me the token with roles:

POST https://login.microsoftonline.com/62765715-2081-4050-bdc7-8c2e178d7424/oauth2/v2.0/token HTTP/2.0
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=1009eb01-33c0-4bf9-ad54-726d50fb18b5
&client_secret=zlr8*************************************
&scope=api:%2F%2F442b3378-34c6-421f-8912-d3f18a004d1c%2F.default
{
  "aud": "api://442b3378-34c6-421f-8912-d3f18a004d1c",
  "iss": "https://sts.windows.net/62765715-2081-4050-bdc7-8c2e178d7424/",
  "iat": 1735085790,
  "nbf": 1735085790,
  "exp": 1735089690,
  "aio": "k2BgYDh97Ul1oVFTEfumuQ1zVuQdBQA=",
  "appid": "1009eb01-33c0-4bf9-ad54-726d50fb18b5",
  "appidacr": "1",
  "idp": "https://sts.windows.net/62765715-2081-4050-bdc7-8c2e178d7424/",
  "oid": "d5760fed-eaf1-4e6e-aed2-a2b65ac0a030",
  "rh": "1.AREAFVd2YoEgUEC9x4wuF410JHgzK0TGNB9CiRLT8YoATRwXAQARAA.",
  "roles": [
    "Vehicles.Read",
    "Vehicles.Write"
  ],
  "sub": "d5760fed-eaf1-4e6e-aed2-a2b65ac0a030",
  "tid": "62765715-2081-4050-bdc7-8c2e178d7424",
  "uti": "4gbiMCOLlk2bJqHrffsaAA",
  "ver": "1.0"
}

Is there any way in Azure to give it access to the above token (or similar, as long as the audience and roles are there) without using client secret? Preferably via DefaultAzureCredential?

Update2:

I have tried the following

enter image description here

New-AzureADServiceAppRoleAssignment `
    -ObjectId e67aa4a7-e487-47b9-8d27-78cf30888f61 `
    -PrincipalId e67aa4a7-e487-47b9-8d27-78cf30888f61 `
    -Id f39a570e-6309-496f-b81a-0de5a9e07e2e `
    -ResourceId 3d73b9d4-b4b6-4741-b1f6-22a7fa6453d2

Output:

New-AzureADServiceAppRoleAssignment: Error occurred while executing NewServicePrincipalAppRoleAssignment 
Code: Request_BadRequest
Message: Permission being assigned was not found on application
RequestId: 8cf83ecf-c707-4621-adfe-52397837d690
DateTimeStamp: Fri, 27 Dec 2024 21:10:58 GMT
Details: PropertyName  - None, PropertyErrorCode  - InvalidUpdate
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed

Update3:

enter image description here

Update 4 I assigned backend-api permissions back to itself, reran above New-AzureADServiceAppRoleAssignment command, still the same result.

enter image description here

Update 5: Success! The command worked with following ids:

enter image description here

enter image description here

Following code returns token with roles

AccessToken token1 = 
    await new DefaultAzureCredential()
                .GetTokenAsync(new TokenRequestContext(
                    ["api://442b3378-34c6-421f-8912-d3f18a004d1c/"]));
  "roles": [
    "Vehicles.Read"
  ],

Solution

  • Note that: To call another Microsoft Entra Application and generate access token using system managed identity you need to assign the permissions to the managed identity.

    Assuming you want to generate token using managed identity in web app service and include roles in it.

    I created a Microsoft Entra ID application and created app role:

    enter image description here

    Assign this app role to system managed identity:

    enter image description here

    Connect-AzureAD
    
    New-AzureADServiceAppRoleAssignment -ObjectId MIObjectID -Id AppRoleID -PrincipalId MIObjectID -ResourceId MicrosoftEntraServicrPrincipalObjID
    

    You can also make use of latest Microsoft Graph PowerShell module.

    enter image description here

    When you check the managed identity in the Enterprise application blade, app role is assigned:

    enter image description here

    Now I used the below code to generate access token using Azure web app system identity:

    using Azure.Core;
    using Azure.Identity;
    
    namespace WebApplication1.Models
    {
        public class TokenService
        {
            public async Task<string> GetAccessTokenAsync()
            {
                string resource = "api://ClientIDOfEntra/"; 
    
                var credential = new DefaultAzureCredential();
    
                var tokenRequestContext = new TokenRequestContext(new[] { resource });
    
                AccessToken token = await credential.GetTokenAsync(tokenRequestContext);
                Console.WriteLine($"Access Token: {token.Token}");
    
                return token.Token;
            }
        }
    }
    

    When published to App service access token generated successfully:

    enter image description here

    Decode the token app roles are displayed:

    enter image description here

    The appid claim includes the Application ID of system managed identity.

    By using the above token, you can call the other application successfully and make sure to use the same scope you are using of client credential flow.