[Deep Dive] The Deep Annoying Dark Art of Configuring an Azure Serverless API Functions to be authenticated with Azure B2C Active Directory Configuration Policy…

I used to think Git was hard to learn, then GitKraken made it easy (tip fedora). Then, I ran into Azure configuring beast. I literally sunk about 2 to 3 days alone just reading blogs, LinkedIn training videos, trying, failing, crying, grieving, therapy session, taking a walk, adopting a pet, watching it die of old age, before I figured out how to configure this monster (jk about pet dying part, except my hair).

I now write it down as a reflection of my torment, suffering in the hope that it will hope enlightening the future generation and maybe, result in them suffering a bit less.

I saw many similar guide but not EXACTLY what I was trying to do. The problem itself is not challenging but to FIND the right information to put into the right field, turned out to be SUCH a unnecessarily challenging task. This is also probably not helped by the fact that I am not super familiar with Azure system and new to serverless and new to Active Directory etc. But hey, you probably stumbled here because you were in similar boat….

This will be work in progress article updated over time.

Let’s start with some key assumptions:

  1. The Azure Serverless app is already running without any authentication. In my case, I build a VERY simple azure serverless app to return the MD5 code of the image uploaded to the end point. There are many guide on how to build simple Serverless app, I will not elaborate on those. You came here most likely related to the configuration/authentication issue anyway, if not, check out the microsoft guide here: https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function.
  2. You have an Azure account of some sort. This is where configuration confusion madness begins… I thought I was the only one but apparently, not. See this post of Tsuyoshi experiencing similar kind of confusion, especially its 1st figure: https://medium.com/@tsuyoshiushio/configuring-microsoft-graph-bindings-for-azure-functions-with-b2c-60fe0b63e81a

High level overview of the steps:

Section 1: Azure AD B2C

  • Create Azure AD B2C
    • This AD B2C stores the customers’ data and keep it separate from staff data of the organization.
  • Create an account for the Azure AD B2C
    • Might be optional. Need to test out more. As long as you have an account that can access the B2C application, you should be okay here.
  • Use that account to create an Azure AD B2C app
    • A app MUST be created AND registered to access the Azure AD B2C
  • Register the Azure AD B2C app
    • A app MUST be created AND registered to access the Azure AD B2C
  • Create a policy for the app
    • Policy is required to set scope etc and obtain the end point.
  • Get the Policy Properties page
    • This page contain the endpoints which the request will be made to.

Section 2: Azure Serverless Function

  • Create the App and Deploying to Azure Portal
    • This app does what you need, for my example, I used a MD5 hash returning to ensure they processed the uploaded data.
  • Enable authentication
    • Set up the proper setting using information from the Azure AD B2C app.

Section 3: Final Testings

  • Postman use OAuth2.0 to get Access Token: https://{Your App Name}.azurewebsites.net/API/{Your Function Name}/
  • Use the ID token as bear token to access service.

Detailed Steps to Connecting Azure AD B2C with Azure Function

Updated as of 2019-12-29T085916EST

Section 1 Azure AD B2C: Create Azure AD B2C tenant

See the source guide: https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant

In short:

  1. On the Azure portal menu or from the Home page, select Create a resource.
  2. Search for Azure Active Directory B2C, and then select Create.
  3. Select Create a new Azure AD B2C Tenant
  4. Enter an Organization name and Initial domain name. Select the Country or region (it can’t be changed later), and then select Create.
  5. Once the tenant creation is complete, select the Create new B2C Tenant

Select B2C Tenant Directory (same Source):

  • To start using your new Azure AD B2C tenant, you need to switch to the directory that contains the tenant.
  • Select the Directory + subscription filter in the top menu of the Azure portal, then select the directory that contains your Azure AD B2C tenant.
  • If at first you don’t see your new Azure B2C tenant in the list, refresh your browser window, then select the Directory + subscription filter again in the top menu.

Section 1 Azure AD B2C: Create a new account within that AD B2C

  • For testing purposes…
  • Not 100% sure if it is necessary.

Section 1 Azure AD B2C: Create “Application”

See the source guide at: https://docs.microsoft.com/en-us/azure/active-directory-b2c/add-web-application?tabs=applications

  1. Sign in to the Azure portal.
  2. Make sure you’re using the directory that contains your Azure AD B2C tenant. Select the Directory + subscription filter in the top menu and choose the directory that contains your tenant.
  3. Choose All services in the top-left corner of the Azure portal, and then search for and select Azure AD B2C.
  4. Select Applications, and then select Add.
  5. Enter a name for the application. For example, webapi1.
  6. For Include web app/ web API and Allow implicit flow, select Yes.
  7. For Reply URL, enter an endpoint where Azure AD B2C should return any tokens that your application requests. In your production application, you might set the reply URL to a value such as https://{REPLACE YOUR APP NAME NERE!}/.auth/login/aad/callback
  8. For App ID URI, enter the identifier used for your web API. The full identifier URI including the domain is generated for you. For example, https://{REPLACE YOUR ORG NAME HERE}.onmicrosoft.com/api.
  9. Click Create.
  10. On the properties page, record the application ID that you’ll use when you configure the web application.

Section 1 Azure AD B2C: Obtain Application ID (aka Client ID):

Refresh the page to visit the app in Azure AD B2C. Under General -> Properties to your left, then copy the Application ID. This will be used later in configuring the Azure Function App.

Section 1 Azure AD B2C: Obtain Keys (aka Client Secret):

Refresh the page to visit the app in Azure AD B2C. Under General -> Keys to your left, then click generate key. Save and the key will appear, these later as it will be part of the necessary information to obtain the Access Key.

Section 1 Azure AD B2C: Register the App

(Source https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=applications) :

  1. Sign in to the Azure portal.
  2. Select the Directory + Subscription icon in the portal toolbar, and then select the directory that contains your Azure AD B2C tenant.
  3. In the Azure portal, search for and select Azure AD B2C.
  4. Select Applications, and then select Add.
  5. Enter a name for the application. For example, webapp1.
  6. For Include web app/ web API and Allow implicit flow, select Yes.
  7. For Reply URL, enter an endpoint where Azure AD B2C should return any tokens that your application requests. https://{REPLACE YOUR APP NAME NERE!}/.auth/login/aad/callback
  8. Select Create to complete the application registration.

Section 1 Azure AD B2C: Create an policy for the app.

Source Guide: https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows

In short,

  1. Sign in to the Azure portal.
  2. Select the Directory + Subscription icon in the portal toolbar, and then select the directory that contains your Azure AD B2C tenant
  3. In the Azure portal, search for and select Azure AD B2C.
  4. Under Policies, select User flows (policies), and then select New user flow.
  5. On the Recommended tab, select the Sign up and sign in user flow.
  6. Enter a Name for the user flow. For example, signupsignin1.
  7. For Identity providers, select Email signup.
  8. For User attributes and claims, choose the claims and attributes that you want to collect and send from the user during sign-up. For example, select Show more, and then choose attributes and claims for Country/RegionDisplay Name, and Postal Code. Click OK.
  9. Click Create to add the user flow. A prefix of B2C_1 is automatically appended to the name.

Section 1 Azure Ad B2C: Get the Policy Properties Page:

Refresh the page to visit  Azure AD B2C. On the left, click on User Flows (policies), then create the policy created in the previous step. On the left side, click on properties, on the right blade, click on “Run user flow”. This should open a new blade, which at the top that list a url like: https://{YOUR B2C NAME}.b2clogin.com/tfp/{YOUR B2C NAME}.onmicrosoft.com/B2C_1_{YOUR POLICY NAME}/v2.0/.well-known/openid-configuration.

Click on that to open a new tab with a XML listing the key endpoints, take note of the following, as you will need them to request the Access token:

"issuer": "https:///{YOUR B2C NAME}.b2clogin.com/tfp/{ID}/b2c_1_api_authentication/v2.0/",
"authorization_endpoint": "https:///{YOUR B2C NAME}.b2clogin.com//{YOUR B2C NAME}.onmicrosoft.com/b2c_1_{YOUR POLICY NAME}/oauth2/v2.0/authorize",
"token_endpoint": "https:///{YOUR B2C NAME}.b2clogin.com//{YOUR B2C NAME}.onmicrosoft.com/b2c_1_{YOUR POLICY NAME}/oauth2/v2.0/token",

Section 2 Azure Serverless Function: Create the function and publishing the function.

This part there are many tutorial. I highly recommend this one using visual studio 2019 to directly publish: https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio.

The goal of this section is to get an app deployed and configured with Azure Portal such that http://{Your App Name}.azurewebsites.net/api/ is at least working. and you tested it by calling it (without authentication and works).

Make sure to test this in the Postman to ensure the endpoint etc is all setup. Google “Azure Function Serverless API tutorial” etc to see tons of guide about how to setup one up. You need at least a kind of hello world app deployed on the http://{Your App Name}.azurewebsites.net/api 

Good luck.

Section 2 Azure Serverless Function: Update security:

Refresh the page, go to the Function Apps in All Resources. Click on the app on the left, click on the Platform Features tab to access the authentication / authorization  in the networking group of links. It is most likely set to OFF currently. Switch it to ON and in the below. You should see the first two figures from this blog: https://blogs.msdn.microsoft.com/stuartleeks/2018/02/19/azure-functions-and-app-service-authentication/. Except, we are not using Facebook for the Azure Serverless authentication/authorization.

Under “Action to take when request it not authenticated”, best to change it to log into Azure Active Directory. Then under the authentication providers, click on Azure Active Directory (which should say Not Configured?).

The new blade should give three choices: Off, Express, Advanced. I wasted about 3 days playing with express but that won’t work with Azure AD B2C as far as I tried.

Switch to Advanced.

  • Client ID: use the application ID you created at the Azure AD B2C earlier.
  • Issuer URL: use the issuer URL from the Azure AD B2C Policy Properties section.
  • Client Secret: use the keys that were generated earlier in Azure AD B2C application section.

That is it. Click okay to save.

Now, the testing part is also equally absurdly obscure.

Section 3 Postman Testing: Getting the Access Token

Create a new post request to the app with the proper endpoint which has PROVEN to work BEFORE you added the authentication. For me it was like

https://{Your App Name}.azurewebsites.net/API/{Your Function Name}/

Go to the Auth tab in the post man for this request.

Set authorization type to OAuth 2.0

Add auth data to “Request Headers”

Then click on the Get New Access Token.

Date/time stamp the token name so you can remember it.

  • Grant type: Authorization Code
  • Callback URL: https://{YOU APP NAME}.azurewebsites.net/.auth/login/aad/callback
  • Auth URL / Access Token URL: Use the information obtained from: Azure AD B2C Policy Properties Page.
  • Client ID: use the application ID you created at the Azure AD B2C earlier.
  • Client Secret: use the keys that were generated earlier in Azure AD B2C application
  • Scope: must used OpenID. Not really sure why. But this was the ONLY scope that worked for me. Similarly, this was indicated in the Policy properties page.
  • State: leave empty.
  • Client Authentication: Send client credentials in body.

Click on request token and you WILL see a new browser window that you can login with any credential in your AD B2C and receive a token BACK!

However, the token you get back is only an id_taken and does not populate the Access Taken field built into Postman. Hence, you have to manually copy and paste the token in a separate request (as bearer token) to get access to the API.

BTW. MAKE SURE THERE IS NO SPACE/NEW LINE CHARACTER at the end of your id_token when copying and pasting as I wasted about 2 days debugging this…

Section 3 Final Testing: Using the Access Token: 

So, if all of  these go as well as hoped, you have properly setup your Azure Function Serverless to authenticate against the Azure AD B2C directory. And this is trigger both at HTTP regular traffic level and as well as API interactions. However, this is merely a super rough proof of concept to show how everything interlock. Usability is still crap and a lot edges can be improved to provide usable endpoints and user experience. In my case, I was able to upload the data of the image and have Azure Function process that to return a MD5 hasb in text form along with a few other things such as some additional parameters sent over. I verified that I get the same results as my local testing against the same end points versus the remote endpoints.

I will revisit the guide to improve its usability in a bit.

Additional relevant references:

  • https://medium.com/@sambowenhughes/how-to-setup-active-directory-b2c-in-microsoft-azure-766f301e28e
  • A simple guide about getting a quick Azure Function app up and authenticate it with Okta: https://scotch.io/tutorials/5-minute-serverless-functions-in-azure-without-an-ide#toc-how-a-client-would-consume-your-secured-serverless-api

Version 1 published: 2019-12-22T164554EST.

Version 2 published: 2019-12-29T085926EST