Using MSI to call another Web/Function App

I see this question come up every so often around how to call another function or web app with MSI that is configured to use the built in Authentication.

The steps to setting up the authentication and authorization can be found in steps 1-3 of this previous blog. The UX has since changed so I will get around to updating the screenshots at somepoint (Oct 2021).
https://blog.brooksjc.com/2020/06/21/accessing-graph-api-with-an-azure-function-through-impersonation/


The key part to making sure the code runs correctly is knowing what to define as the audience or scope of who you are getting a token for from MSI to pass to the app. If the app regisration is configured with the URL of the app service you can use that as the audience in the source app, otherwise use the app registration ID.

Configuration on the Destination App

Code also available here: https://github.com/jcbrooks92/MSICallingAnotherAppWithEasyAuth

In the source code below the values you’ll want to add as app settings are the endpoint and URL. As described in the comments the URL is the destination app service and the endpoint is the audience value discussed above.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Azure.Services.AppAuthentication;

namespace Company.Function
{

    public static class MSIFunction
    {
        private static readonly HttpClient client = new HttpClient();

        [FunctionName("MSIFunction")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            var tokenProvider = new AzureServiceTokenProvider();

            var endpoint = Environment.GetEnvironmentVariable("endpoint"); // Env variable - The audience of the app registration or identifier in AAD
            var url = Environment.GetEnvironmentVariable("url"); //Env variable - URL of the web app or function app you're calling including https ie : https://www.microsoft.com

                        try
                {
                string accessToken = await tokenProvider.GetAccessTokenAsync(endpoint); //example: https://database.usgovcloudapi.net

                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

                    HttpResponseMessage response = await client.GetAsync(url);
                    var contents = await response.Content.ReadAsStringAsync();

                    log.LogInformation(response.ToString());
                //log.Info(contents);
                return new OkObjectResult(response.ToString());

            }
            catch (Exception e)
                {
                    log.LogInformation(e.ToString());
                //return req.CreateErrorResponse(HttpStatusCode.BadRequest, e.ToString());
                return new BadRequestObjectResult(e.ToString());
                }
           
        }
    }
}