I'm trying to assign an app role to my function app's system-assigned managed identity.
I believe I've followed all the required steps but my access token (obtained through DefaultAzureCredential()) still doesn't contain the required role (Mail.Send).
Here's what I've done:
I created an app registration and added the Microsoft Graph Mail.Send permission with Type: Application and obtained admin consent.
I created an app role to use Mail.Send with.. Allowed member types: Applications, Value: Mail.Send, State: Enabled.
I assigned the role to my function app's managed identity. I did this using Azure CLI following these instructions. I then can confirm that the permission appears under my managed identity's Permissions in the Portal with... Claim value: Mail.Send, Type: Application, Granted through: Admin Consent, Granted by: An administrator.
I have created a function App and enabled System assigned managed identity.
Assign Send.Mail role to System Managed Identity of function App using below PowerShell Script.
Connect-AzureAD -TenantId <Tenant_ID>
$TenantID="<Tenant_ID>"
$GraphAppId = "00000003-0000-0000-c000-000000000000"
$DisplayNameOfMSI="Display Name of Managed Identity"
$PermissionName = "Mail.Send"
$ObjectId= "Object ID of managed identity"
Start-Sleep -Seconds 10
$GraphServicePrincipal = Get-AzureADServicePrincipal -Filter "appId eq '$GraphAppId'"
New-AzureAdServiceAppRoleAssignment -ObjectId <Object_ID> -PrincipalId <Principal_ID> -ResourceId $GraphServicePrincipal.ObjectId -Id <AppRole_Id>
Function code to obtain access token for managed identity with application role.
public class Function1
{
private readonly ILogger<Function1> _logger;
public Function1(ILogger<Function1> logger)
{
_logger = logger;
}
[Function("Function1")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
string jwtToken = await GetJwtTokenUsingSystemManagedIdentity();
return new OkObjectResult($"JWT Token: {jwtToken}");
}
private static async Task<string> GetJwtTokenUsingSystemManagedIdentity()
{
string resource = "https://graph.microsoft.com/.default";
var credential = new DefaultAzureCredential();
var tokenRequestContext = new Azure.Core.TokenRequestContext(new[] { resource });
var token = await credential.GetTokenAsync(tokenRequestContext);
return token.Token;
}
}
Connected! You are now viewing logs of Function runs in the current Code + Test panel. To see all the logs for this Function, please go to 'Logs' from the Function menu.
2025-01-27T08:40:20Z [Information] Executing 'Functions.Function1' (Reason='This function was programmatically called via the host APIs.', Id=394cf91b-4b2c-4335-9d5a-33fab65735ad)
2025-01-27T08:40:21Z [Information] C# HTTP trigger function processed a request.
2025-01-27T08:40:21Z [Information] Executing OkObjectResult, writing value of type 'System.String'.
2025-01-27T08:40:22Z [Information] Executed 'Functions.Function1' (Succeeded, Id=394cf91b-4b2c-4335-9d5a-33fab65735ad, Duration=2002ms)
Able to generate the Access token in functionapp:
Decoded Access token and able to see the assigned role Mail.Send
: