Client App Calling An Azure Function With AAD

I recently needed to create a client app that used an AAD application to authenticate with an Azure Function that was configured with the AAD Easy Auth flow. Documenting it here seemed like it might add value to the interwebz.

  • Create a new Azure Function App.
    • Once it is created, create a simple function that uses an HTTP trigger:

      public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
      {
          log.LogInformation("C# HTTP trigger function processed a request.");
          return (ActionResult)new OkObjectResult("Hello world");
      }

  • Set up auth for the function
    • Under the Integrate section for that function, change Authorization level to Anonymous.
    • Go back to the function and click Get function URL. Save that for later.
    • Back in your function app, click Platform Features and then choose Authentication / Authorization.
      • Turn on App Service Authentication
      • Change "Action to take when request is not authenticated" to "Log in with Azure Active Directory".
      • Click on Azure Active Directory to configure it.
      • Use the Express flow and click OK.
      • Note the client ID and save it for later.
      • Once that's done, click on Azure Active Directory to modify the configuration. Click on the Advanced tab. Add the URL to your function app in the Allowed Token Audiences. For example, my app already had "https://bentestfunc.azurewebsites.net/.auth/login/aad/callback" but I had to add "https://bentestfunc.azurewebsites.net". I missed this step for a long time and kept getting 401's.
  • Open Azure Active Directory to create an AAD app for your client.
    • Click on App registrations and then "New application registration"
    • Give it a name and choose "Web app /API". (Native would probably work too but my flow didn't involve a user giving permission.) Use the function app URL as the sign-on URL. I'm not sure if it matters if it's that exact string or just a unique URL.
    • Click Create
    • Once it has been created, click Settings > Required Permissions.
    • Click Add and search for the app Id that you created in the Easy Auth flow for your function app.
    • Check the box to give delegated permission to access your function app.
    • Accept all the panels and save those changes.
    • In the Settings panel, click Keys and generate a key. Save that for later.
  • Get the App Uri ID for your function app
    • In Azure Active Directory, search the app registrations for the app that was created in the Easy Auth flow of your Azure Function.
    • Select it and click Settings > Properties. Copy the App Id Url.
  • Create a console app to test the client access
    • Use a function like this to access your Azure Function App

      static async Task Post()
      {
          string aadInstance = "https://login.windows.net/{0}";
          string tenant = "yourtenant";
          string serviceResourceId = "AppIdUrl from your Azure Function AAD app goes here";
          string clientId = "app id of your client AAD app";
          string appKey = "app key of your client AAD app";

          // Get auth token and add the access token to the authorization header of the request.
          var httpClient = new HttpClient();
          var authContext = new AuthenticationContext(string.Format(CultureInfo.InvariantCulture, aadInstance, tenant));
          var clientCredential = new ClientCredential(clientId, appKey);
          AuthenticationResult result = await authContext.AcquireTokenAsync(serviceResourceId, clientCredential);
          httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

           // Send the request and read the response
          HttpResponseMessage response = await httpClient.GetAsync("The function url that you saved from earlier");
          Console.WriteLine($"{(int)(response.StatusCode)} {response.ReasonPhrase}");
          Console.WriteLine(await response.Content.ReadAsStringAsync());
      }

Will this work for you? I hope so! But I'm far from an expert. Hopefully it helps someone or at least points you in the right direction.