Share via


Azure Active Directory B2C and Azure Functions

Hello everyone,

In the light of my recent post about B2C and ASP.NET Core web APIs, I thought I'd shed some light on how to make Azure Functions work with B2C, because it may not be immediately obvious from the portal's interface. Actually, all the information is already in this article, and it still applies: https://blogs.msdn.microsoft.com/appserviceteam/2016/06/22/app-service-auth-and-azure-ad-b2c/

 
Setting up B2C authentication for your Azure Functions App is actually really easy:

  1. Create your Azure Functions App and write down the URL

    1. E.g. https://myazurefunctions.azurewebsites.net (make sure to make it a HTTPS URL)

     

  2. Configure your application in Azure Active Directory B2C:

    1. Write down the Application ID
    2. Add a reply URL for your Functions App, adding the suffix /.auth/login/aad/callback. E.g. https://myazurefunctions.azurewebsites.net/.auth/login/aad/callback

     

    The configuration should look something like this:

     

  3. Get the Metadata Endpoint URL for your Sign-in policy

    1. If you open the details of your sign-in policy, you'll find it right at the top. E.g.:

       

  4. In your Functions App, on the bottom left select "Function app settings" and go to "Configure authentication":

     

  5. Turn on authentication and select Azure Active Directory:

     

  6. Select the advanced settings and enter the following values:

    1. Client ID: The Application ID which you copied in step 2. a.
    2. Issuer Url: The Metadata Endpoint URL from step 3.

     

  7. Save your settings and you're done!

 

Once the changes have taken effect, if you try to test your Azure Function without an Authorization header, you'll get the following error – as expected:

 

However, with a valid bearer token, you're up and running again:

 

I hope this made your life a little bit easier.

Cheers,
Helge Mahrt

Comments

  • Anonymous
    March 31, 2017
    Helge,This (and the referenced post from last year too) is helpful indeed. However, neither post actually shows invoking the FunctionApp/Function via a simple B2C policy. I've been trying to get mine to work, but to no avail. Do you all have more thorough examples in posts or on GitHub that work? The /.auth/login/aad/callback doesn't seem to be working in the current version of Functions, from my experience anyhow.
    • Anonymous
      March 31, 2017
      Hello Jarrod,Once you set this up, the functions app will behave like any other web api that's been secured with B2C. You'll need to provide an Authorization header with a valid access token during the HTTP calls. You need to acquire this token in the client which calls the web API - which also presents the UI to the user - e.g. a web app or a mobile client etc. This guide shows how to acquire the access token in a .NET desktop application and use it to call a web api: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-native-dotnetAnd this one shows the same, but calling from an ASP.NET web app: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-web-api-dotnetHope this helps,Helge
      • Anonymous
        March 31, 2017
        Hi Helge,That does indeed help. I was assuming that the /.auth/login/aad/callback did something unique, but that's what I get for assuming...Thank you very much for the quick response, it helps a lot.
      • Anonymous
        August 01, 2017
        The comment has been removed
        • Anonymous
          October 05, 2017
          Hello Amirsasson,Sorry for the delay, I've been rather busy these past months. I was able to reproduce the behavior when trying to log into my Function App in the browser with a Facebook user account which had never logged into my B2C before. That triggered the Sign-up flow, but if you configured your Functions App according to this blog post you only allowed the Sign-in flow (assuming that you always receive the token of a signed up user, because the API doesn't have a UI and you'd handle the Sign-up flow in your UI). You can solve this by configuring a "Sign-up or sign-in" policy.Hope this helps,Helge
  • Anonymous
    May 16, 2017
    Hi Helge, I was able to get most of this working thanks so much for putting it together. One thing I wasn't clear about was how I'd go about getting the bearer token. I set the callback URL to another function in the same function app but it, of course, couldn't authenticate and I ended up in a bit of a loop. This despite setting the permissions on that other function to be anonymous. It seem like the authorization overrides that. In my scenario I'm attempting to do everything through functions rather than calling into a web application. I'm considering setting up another function app whose sole responsibility is to exchange the authorization code for an access token. Is there, perhaps, another way around that?Thanks,Simon
    • Anonymous
      May 18, 2017
      IIRC, you should be able to get the Bearer token via the ClaimsPrincipal. E.g. I use this helper to get the B2C user id:[code language="csharp"]public static class B2cHelper{ public static string UserID { get { return ClaimsPrincipal.Current?.Claims .FirstOrDefault(x => x.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value; } }}[/code]
  • Anonymous
    May 18, 2017
    Thank you Helge, a very good decent article to start with.
  • Anonymous
    October 04, 2017
    Thanks for the awesome article. One thing that just doesn't make sense to me is why it's at the Function App "Family level" and not the "Per Function Level". There's no way to create a Function App with unauthenticated endpoints AND authenticated endpoints :(
    • Anonymous
      October 05, 2017
      Thanks! I'm glad you liked it :)I'm not sure if the product group has anything in the pipeline, but I think it's a technical limitation. Function Apps, under the hood, are also Web Apps. That becomes apparent when you dig deeper into the settings. For Web Apps, it's either you protection everything - in kind of an external approach; wrap the whole thing in AAD or whatever you select - or, if you need granularity, you need access to the code. As we don't have access to the code that runs our code in Functions Apps - because we want to forget about all that infrastructure - that option is not available.My suggestion: As additional Function Apps are "free" (you only pay for when your code runs), I'd create one instance for authenticated endpoints and one for open ones.
  • Anonymous
    October 07, 2017
    10/7/2017 - please excuse a few noob and possibly misguided questions... First, given its been 7 months , is this guide the the register app feature? Is it still the easiest way to authenticate an Azure function against AAD ? Is there really no way to configure Azure functions to auth against AAD without an separate App ? Default AAD created vs AAD B2C? Thanks!
    • Anonymous
      October 09, 2017
      Hello No Sun Beach,Not sure I got all your questions right. If you provide me with more details I'll try to answer as best as I can. :)As far as I know, this is till the only way to protect your Functions App with either AAD or B2C. I'm not sure what separate app you're referring to. You have your Functions App and in its configuration settings you can set up auth against AAD or B2C. Cheers,Helge
  • Anonymous
    February 01, 2018
    Could this be used for a mobile or web all to log into B2C, then also send the resource token to Cosmos DB? https://blogs.msdn.microsoft.com/cloud_solution_architect/2014/12/09/permissions-in-azure-documentdb/
  • Anonymous
    April 28, 2018
    Hi, I tried and Azure AD B2C works with Azure Functions V1, but I tried with V2 and could not make it work.
  • Anonymous
    August 06, 2018
    Hello, excellent publication, I made the step by step as you, but I am getting this error at the moment I make the call of my function by the web browser (I enter my b2c credentials) and then I get this:The page can not be displayed because an internal server error has occurred.Any idea why it happens to me?Thank you.Regards.