Using Azure AD B2C to Authenticate iOS App Users

Michael Collins
Neudesic Innovation
8 min readFeb 8, 2022
The image shows the log in form from Azure Active Directory B2C presented in a modal view on an iPad.

In my previous post, I demonstrated how to use the Microsoft Authentication Library for JavaScript to implement log in and log out features for a web application. In this post, I will show how to use Azure Active Directory B2C to provide user authentication for a mobile application running on an iPhone or iPad device. As I mentioned in the previous post, Microsoft makes several versions of the Microsoft Authentication Library (MSAL) for different platforms. We will use the Microsoft Authentication Library for iOS and macOS to implement the log in and log out features.

This is the ninth 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

Create an iOS Application

The first step to authenticating users is to build the iOS application that we will want to protect using Azure Active Directory B2C. At the time this post was written, Xcode 13.2.1 is the latest version and SwiftUI 3 is the current version of SwiftUI. I will be demonstrating using MSAL with SwiftUI 3 using the newer SwiftUI application model.

Create a starter SwiftUI application following these steps:

  1. Open Xcode and create a new Xcode project.
  2. Choose the App template for the iOS platform.
  3. Enter a name for the new app. I used ProjectCenter. Choose SwiftUI for the interface setting and Swift for the language. You do not need to include tests or CoreData support at this time.
  4. Click Next and pick the directory where your new project should be created.

Register the Application with Azure Active Directory B2C

I will next go back to Azure Portal and add register my iOS application. If you read through my previous post, I registered the application there. In this post, I am going to build on that by adding the registration for my iOS application:

  1. Open the Azure Portal in a web browser and navigate to the app registration that you created in the previous post; or create a new app registration if necessary.
  2. Click on the Authentication link in the left navigation bar for your app registration.
  3. Click the Add a platform button.
  4. Select iOS/macOS from the list of platforms.
  5. Enter the bundle ID for the iOS application that you created. If you need this, go back to Xcode and click on the project in the Project navigator. Then click on the target for your application executable and navigate to the General tab. Use the value in the Bundle Identifier field.
  6. Click the Configure button to register the iOS application.

When the page refreshes, you should see your iOS app with your bundle identifier. The redirect URI will be automatically generated by Azure Portal and will take the form msauth.<bundle-id>://auth. For example, my bundle identifier is me.michaelfcollins3.ProjectCenter, so my redirect URI is msauth.me.michaelfcollins3.ProjectCenter://auth.

Add MSAL Using Swift Package Manager

I next need to add the MSAL framework to my application so that I can use it. I will add a dependency on MSAL using Swift Package Manager:

  1. In Xcode, choose the File → Add Packages menu option.
  2. In the search box, enter the URL of the MSAL framework’s GitHub repository: https://github.com/AzureAD/microsoft-authentication-library-for-objc.git.
  3. For the Dependency Rule field, select Up to Next Major Version.
  4. For the Add to Project field, make sure that your main project is selected.
  5. Click the Add Package button.

Configure the iOS Application

In order to link the iOS application and Azure Active Directory B2C together, we need to add some metadata to the Info.plist file for the application. In Xcode, go to the Info tab in the project and add the following:

  1. Expand URL Types and add a new URL type. Set the URL Schemes field to msauth.<bundle-id>.
  2. In the Custom iOS Target Properties section, add a new key named LSApplicationQueriesSchemes. Change the type of the new item to an array. Add two String values msauthv2 and msauthv3.
  3. Change to the Signing & Capabilities tab of the iOS target. Click the + Capability button and choose Keychain Sharing from the list of capabilities. In the Keychain Sharing capability, click the + button to add a new keychain group and replace the default value with com.microsoft.adalcache.

These settings are used for URL resolution when the app is installed on an iPhone or iPad. By registering the URL schema msauth.<bundle-id>, you are telling iOS that your app can handle URL requests using that scheme. For example, if my bundle identifier is me.michaelfcollins3.ProjectCenter and my URL scheme is msauth.me.michaelfcollins3.ProjectCenter, then if iOS receives a request to open the URL msauth.me.michaelfcollins3.ProjectCenter://app/home, iOS will launch my application and will send my app the URL to perform an action or to navigate to a specific view.

The LSApplicationQueriesSchemes array is used to declare which URL schemes our application is interested in. For interoperability with Microsoft Authenticator app, we define msauthv2 and msauthv3, which are both handled using Microsoft Authenticator.

The com.microsoft.adalcache keychain group is used by MSAL to store authentication information in a private keychain. The keychain can be shared and used by other applications or extensions to enable single sign-on across applications. For more information on keychain sharing, read this.

Providing a UIViewController to MSAL

I am creating a SwiftUI application, but there is an immediate problem that I need to resolve before I move forward with implementing my log in and log out feature. MSAL is based on UIKit and displays the custom policy web UI in a modal view controller. In order to display the UI, we need to provide a parent UIViewController that MSAL can use to present its UI. This provides us with an issue because SwiftUI doesn’t provide us access to a view controller. We can use the UIViewControllerRepresentable protocol to create a UIViewController that then presents the MSAL UI, but then we’re going to display an empty view controller which is kind of confusing from a UI perspective. Fortunately, we have another option.

SwiftUI implements a different application model than UIKit. SwiftUI uses the App protocol instead of an UIApplicationDelegate object. But SwiftUI does allow us to define a traditional UIApplicationDelegate object to handle application lifecycle events and interoperate with older libraries. By using the @UIApplicationDelegateAdaptor property wrapper, we can specify a UIApplicationDelegate object that SwiftUI should defer to for handling the application lifecycle events.

Once we are able to handle application lifecycle events, we can take advantage of the scene framework introduced in iOS 13. While UIApplicationDelegate objects handle application lifecycle events, UI events have been moved to scenes and are handled by objects implementing the UISceneDelegate or UIWindowSceneDelegate protocols. We can take advantage of UIWindowSceneDelegate specifically to obtain the root view controller for SwiftUI.

I’m going to start by implementing the AppDelegate type:

My AppDelegate class implements the application(_:configurationForConnecting:options:) function that is called to provide the configuration for a new application scene. Right now, our application only has one scene, so this is fairly straightforward to implement. The important part of the implementation is setting the UISceneConfiguration.delegateClass property. SwiftUI provides its own scene delegate, but it does allow you to customize the scene by configuring your own scene delegate and SwiftUI’s scene delegate will forward function calls to your custom scene delegate.

My MainSceneDelegate class implements the UIWindowSceneDelegate protocol. The window property is never set in SwiftUI. It is set in SwiftUI’s scene delegate, but not in our custom scene delegate. However, I can cast the scene argument in scene(_:willConnectTo:options:) function to a UIWindowScene object and get the window from it. Once I have the window, I can get the root view controller for the SwiftUI scene. Internally, SwiftUI will use a UIHostingController object as the root view controller for the scene. We’ll store the reference to the UIHostingController object in the rootViewController property.

Another trick is that MainSceneDelegate also implements the ObservableObject protocol. This is important because even though we don’t have any @Published properties, because MainSceneDelegate conforms to ObservableObject, MainSceneDelegate will automatically be exposed to all views in the scene through the SwiftUI environment and we can reference it in our SwiftUI views.

In my ProjectCenterApp type, I am creating the MSALPublicClientApplication singleton instance in the initializer. I’m letting the app crash if the configuration fails for some reason. It’s probably not what you want to do in production. When the scene is rendered, I am storing the reference to the singleton MSALPublicClientApplication in ContentView’s environment and it will be available to all subviews.

Finally, here is my ContentView implementation:

ContentView uses a boolean state variable to show either the Log In or Log Out button. ContentView reads the scene delegate from the environment as well as the singleton instance of the MSALPublicClientApplication type. The logIn function will authenticate the user by displaying a modal view controller that presents the Azure Active Directory B2C web UI. The logOut function does the same but to log the user out.

Testing the Application

My iOS application can be tested either in the iOS simulator or on a device. After running the application in Xcode, I am prompted to log in with the Log In button:

iOS application showing the Log In button

When I tap the Log In button, I am prompted for permission to access the b2clogin.com domain to sign in to the application:

The permission prompt to use b2clogin.com to sign into the application

If I approve the permission, I am presented with the Azure Active Directory B2C web UI for logging in:

The log in form from Azure Active Directory B2C

After submitting the form, the modal is dismissed and I am presented with the Log Out button to indicate that I have successfully logged in:

The Log Out button is showing to indicate that the user successfully logged in

If I tap the Log Out button, I am logged out of the application and taken back to the Log In button:

Back to the Log In button after logging out

On an iPad, the modal will be displayed in form sheet mode:

The image shows the log in form from Azure Active Directory B2C presented in a modal view on an iPad.
The Azure Active Directory B2C log in form showing in a form sheet modal on iPad

Where Did We Go?

As in the last post, in this post I have shown you how to use your Azure Active Directory B2C tenant to provide user authentication for a mobile application running on an iPhone or iPad. I have shown you how to integrate the MSAL library for iOS into a modern SwiftUI application and how to present the log in screen. Now you can wire up your own applications to your Azure Active Directory B2C tenant to support sign up or log in user stories.

--

--

Michael Collins
Neudesic Innovation

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