Authenticate Azure Static Web App Users Using Azure AD B2C

Michael Collins
Neudesic Innovation
9 min readFeb 19, 2022
Photo by Shahadat Rahman on Unsplash

Hands down, my favorite new Azure feature in quite some time is Static Web Apps. Static Web Apps can be free for simple websites or reasonable inexpensive ($9/month) for a few more features. I plan on posting more about Static Web Apps in the future, but in this post I wanted to continue with my Azure Active Directory B2C series and show you how to add user authentication for Static Web Apps using Azure Active Directory B2C and OpenID Connect.

This is the twelfth post in a series on Azure Active Directory B2C and how to use Azure Active Directory B2C to create an identity management system for a Software-as-a-Service application. If you are new to this series, I recommend reading the earlier posts in the series:

  1. Building Application Identity Solutions using Azure AD B2C
  2. Configure Azure AD B2C For Customization
  3. Understanding the B2C Directory
  4. Sign Up or Sign In Users With Azure AD B2C: Part 1
  5. Sign Up New Users Using Azure AD B2C
  6. Log In With Local Accounts on Azure AD B2C
  7. Combining Sign Up and Sign In Into a Single Policy Using Azure AD B2C
  8. Using Azure AD B2C to Authenticate Web App Users
  9. Using Azure AD B2C to Authenticate iOS App Users
  10. Using Azure AD B2C to Authenticate Android App Users
  11. Validating User Passwords for Azure AD B2C

Why Use App Service Authentication with Static Web Apps?

In a previous post, I demonstrated how to use the Microsoft Authentication Library (MSAL) for JavaScript to implement the sign up and log in services for a Vue.js web application. There was another way that I could have implemented authentication, and it is built into Static Web Apps. In fact, it’s built into Static Web App’s parent technology: App Service.

App Service supports built-in authentication services using identity providers such as Azure Active Directory, Facebook, Google, Twitter, and external OpenID Connect providers. As an application of App Service, apps hosted using Static Web Apps inherit this feature. But why would one choose to use the built-in authentication for a static web app instead of using MSAL like I demonstrated in my earlier article?

There are a couple of reasons:

  1. Not every static site is a web application. A static site may hold documentation or downloads that you want to protect to only allow authorized users to reach the files and to download the files or view them in a web browser.
  2. Static Web Apps can include Azure Functions as part of the application. By using built-in authentication, calls to Azure Functions happen within the context of the security model and Azure Functions can be authorized based on the user’s identity and roles.

Even for a single page application like a Vue.js application or Angular application, using the built-in authentication may be much easier than having to roll your own wrapper around MSAL.

Create a Single Page Application

To begin my demonstration, I am going to repeat the process of creating a single page application using the Vue.js framework. I will open a terminal on my laptop and create the application using the Vue CLI:

vue create helloworld

I will then go to GitHub and will create a new repository for my web application. I will copy the Git repository URL and will register it with my application, then I will push the changes up to GItHub:

cd helloworld
git remote add origin <github-repo-url>
git push -u origin main

Next, I will create the Static Web App that will host my application:

  1. Open Azure Portal in a web browser. If necessary, switch to the directory for your Azure subscription (not the directory for your Azure Active Directory B2C tenant).
  2. Click the Create a resource link.
  3. In the search field, type Static Web App and press Enter or click the search result.
  4. Click the Create button to create a Static Web App resource.
  5. Select or create a new resource group for the Static Web App resource.
  6. In the Name field, enter a name that you want to use for the Static Web App. The name is not used for the DNS name. You can configure the DNS name later, but a default DNS name will be chosen for you automatically.
  7. For the Plan type field, you will need to choose Standard. The free plan for Static Web Apps does not support custom OpenID Connect providers for authentication, so you must go with the paid plan type. The pain plan will cost $9/month.
  8. For the Azure Functions and staging details field, choose the region where you want the functions and web app to be hosted.
  9. For the Deployment details field, choose GitHub.
  10. Click the Sign in with GitHub button.
  11. In the Organization field, choose your GitHub account or an organization that you are a member of.
  12. In the Repository field, choose the repository that you created earlier to host the source code for your web app.
  13. In the Branch field, choose main.
  14. In the Build Details section that appears, choose Vue.js for the Build Presets drop-down list.
  15. Use the default (/) for the App location field.
  16. Leave the Api location field empty.
  17. Leave the default (dist) for the Output location field.
  18. Click the Review + create button.
  19. Click the Create button to create the Static Web App.
  20. After the Static Web App is created, go to the new resource. Copy the domain name for the Static Web App and save it. You will need it for the next section.

When you create the Static Web App, Azure will automatically generate a deployment script that uses GitHub Actions to deploy your web app to the Static Web App host when changes are committed to the main branch. You can check GitHub to see when the workflow completes, or keep refreshing the static web app host until the Vue.js starting homepage appears.

Create the App Registration

Before we can add authentication to the web application, we need to register the application with Azure Active Directory B2C. In the earlier post, we only registered the application but did not create a client secret. This was because the application was publicly available to download and a client secret could have been easily compromised. When we use Static Web Apps with built-in authentication, the authentication occurs on the server side between the Static Web Apps instance and the Azure Active Directory B2C tenant, so we will use a client secret in this case to authenticate the host to the Azure Active Directory B2C tenant.

  1. Open Azure Portal and switch to the directory for the Azure Active Directory B2C tenant.
  2. Open the Azure Active Directory B2C portal.
  3. In the left navigation menu, click the App registrations link.
  4. Click the New registration link at the top.
  5. In the Name field, enter the display name that you want users to see for your application. This can be changed later.
  6. In the Supported account types field, choose Accounts in any identity provider or organizational directory.
  7. In the Redirect URI section, choose Web for the platform. For the Redirect URI, enter https://<static-web-app-domain-name>/.auth/login/b2c/callback
  8. Make sure that Grant admin content to opened and offlineaccess permissions is checked.
  9. Click the Register button.

We next need to create the client secret used for server-to-server authentication:

  1. From the application’s Overview page, copy and save the value of the Application (client) ID field for the next section.
  2. Click the Certificates & secrets link in the left navigation menu.
  3. Click the New client secret link.
  4. Enter the name of the web application in the Description field.
  5. Choose an expiration period for the client secret.
  6. Click the Add button.
  7. Copy the client secret value and save it for the next section.

Configure the Static Web App

The OAuth/OpenID Connect client identifier and secret values need to be added to the configuration for the Static Web App. These values are never stored in your repository, so you do not need to worry about exposing those values there.

⚠️ The client secret value could/should be stored in Key Vault. I’m not going to demo that in this article, but you should store the value there. For more information, read this.

  1. In Azure Portal, switch to the directory for your Azure Subscription.
  2. Navigate to your Static Web App.
  3. In the left navigation menu, click Configuration.
  4. Click Add and add a setting named B2C_CLIENT_ID and store the application identifier in that value.
  5. Click Add and add a setting named B2C_CLIENT_SECRET and store the secret key in that value.
  6. Click the Save button at the top to save the new configuration settings.

Next, create a file named staticwebapp.config.json in the root directory of your web application. Copy the following content into staticwebapp.config.json. Be sure to replace the wellKnownopenIdConfiguration value with your Azure Active Directory B2C tenant name.

This configuration turns off all of the built-in identity providers and defines a new OpenID Connect identity provider using your Azure Active Directory B2C tenant. The configuration requires that all requests be authenticated in order to download any of the web application files. When the user first attempts to connect to your web application, Static Web App will see that the user is unauthenticated and will redirect the user to the /.auth/login/b2c address. This redirect will initiate the OpenID Connect/OAuth 2.0 flow to authenticate the user. After the user authenticates, they will be redirected to /.auth/login/b2c/callback where Static Web App will process the response and extract the ID and access tokens and create the user’s session.

If you try to authenticate at this point, you will be redirected to Azure Active Directory B2C and can sign in using a username and password or sign up, but the redirect is going to fail. The reason for this is that our Azure Active Directory B2C custom policies do not return all of the information that is needed. If you will recall, I built the custom policies to only do the bare minimum. In order for Azure Active Directory B2C to work, we need to return one additional field in the identity token: the user’s display name. The display name can be present in either the displayName or name field. I will update the custom policies next.

Returning the User’s Name

I am back looking at my custom policies. I did define the displayName claim and I am initializing it with the user’s username and persisting it to the directory. I could go through all of the work to expose the displayName claim and output it from my relying parties, but I don’t need to do that at this point. Since the displayName and username match, the username is stored in the signInName claim and I can return that directly from the relying party policies and change the name to name or displayName.

I will start by updating my B2C_1A_SIGNUP policy:

You will notice that I defined a new <OutputClaim> element referencing the signInName claim. I am outputting the claim with the name name. This <OutputClaim> will cause the name claim to appear in the JWT that is issued by the relying party policy.

I made the same changes to the B2C_1A_LOGIN and B2C_1A_SIGNUPORLOGIN policies:

Go back to the Azure Portal, switch to the Azure Active Directory B2C directory, and then upload the updated custom policies, making sure to overwrite the earlier versions. Then open up a web browser and attempt to open you web application in the browser. You should be prompted to log in, and once you log in, you will be redirected to your web application.

Viewing the User’s Information

A web application that is using Static Web App’s built-in authentication service can obtain information about the user and the claims returned from the Azure Active Directory B2C. After you log into your web application, open a JavaScript Console using the Developer Tools for your web browser. Enter the following commands into the console:

This will output the array of claims, the identity provider, the user’s unique identifier, and the user’s username if the user is authenticated.

The user information that is available to the web application

Where Have We Gone?

We now have two ways to use Azure Active Directory B2C to log into a single page web application. We can either use the built-in identity provider support or use the Microsoft Authentication Library for JavaScript. But for non-single page applications, we have also shown how we can use Azure Active Directory B2C to protect any kind of static web content and require user identities to be known.

:warning: The built-in identity provider is not always the best way to go for authenticating users. If your web app is going to use the built-in Azure Functions support to implement your backend logic, then this approach will work. If your application needs to invoke REST APIs going through Azure’s API Management gateway, you may be better off going with MSAL to get direct access to the access token.

--

--

Michael Collins
Neudesic Innovation

Senior Director of Application Innovation at Neudesic; Software developer; confused father