avatarsimbu

Summary

The provided content is a technical guide on securing Flutter applications using Microsoft technologies, specifically focusing on authenticating a Flutter app on iOS devices using Azure Active Directory (Azure AD) and the Microsoft Authentication Library (MSAL).

Abstract

The article is the fourth installment in a series dedicated to integrating Microsoft's security features into Flutter applications. It details the process of authenticating users on iOS devices by leveraging Azure AD and MSAL. The author outlines the necessary steps to register the application in Azure AD, configure the Flutter project with the correct settings, and implement the authentication service using the azure_ad_authentication Dart package. The guide includes troubleshooting tips for common configuration errors and emphasizes the importance of using Microsoft's libraries for maintaining security. The author also provides insights into the benefits of abstracting platform-specific MSAL implementations and the use of secret configuration files for testing against live Azure AD services.

Opinions

  • The author expresses a preference for relying on Microsoft's client code for authentication due to the ease of updating the package for security patches.
  • The choice of the azure_ad_authentication package is justified by its recent updates and high pub score, indicating reliability and community trust.
  • The author values the security benefits of using the shared system web browser for authentication requests and the caching of authenticated accounts provided by MSAL.
  • Frustration is conveyed regarding a configuration error that was difficult to diagnose due to the generic "CONFIG_ERROR" message, highlighting the need for better error reporting in third-party libraries.
  • The author appreciates the ability to debug deeply nested plugin source code in Xcode, which helped resolve the configuration issue.
  • The importance of aligning the redirect URL in the app's configuration with the one specified in the Azure app registration is emphasized to ensure proper authentication flow.
Join Medium to view all my articles.

Flutter — Microsoft API Management secured with AD — MSAL for iOS

This is the forth part of a mini series to show how to secure your Flutter applications using Microsoft technologies:

  1. Web API — Setting up your Web API with Visual Studio.
  2. APIM Service — Creating an API management service in Azure.
  3. Secure Gateway — Securing requests through the API gateway.
  4. MSAL — Authenticating your Flutter app on iOS.
  5. MSAL — Authenticating your Flutter app on Android.
  6. MSAL — Authenticating your Flutter app on the Web.
  7. Hosted API — Hosting your Web API’s in Azure.
  8. Secure Hosted API — Secure requests with the APIM Gateway

In this article we show how to get an access token by authenticating against an Azure AD on an iPhone.

Azure Authentication Flow

The first step was to register the application in my Azure Active Directory:

Registered Applications

Then I added a login button and code to the login screen to make the call to the new Authentication service and store the access token on success:

onPressed: () => ref
                .watch(authenticationServiceProvider)
                .signIn()
                .then((value) => storeToken(ref, value)),

The authentication service uses a package azure_ad_authentication to support making calls to the Microsoft Access Layer (MSAL) on iOS, Android and the web as each require platform specific setup that you can find in the package notes.

You can find more details on each step in the XP section below.

Ta Da

Login screen when the app runs
Signing in
Redirected to home page when the access token is received

XP

Registering the application in Azure AD

Login into your Azure Portal and select Azure Active Directory and then App registrations from the menu.

Click on “New registration” and name your application, select an account type and register it.

Register your App in you Azure AD

Make a note of the client ID and then click on endpoints and note the auth url.

Client ID
Authorisation endpoint

Next click on the Authentication sub-menu and Add a platform:

Select a platform
Enter a bundle id

The bundle id just needs to be unique so works well:

That’s it, your app is registered.

I then added the authority, client Id and scopesto the app_config_.json file:

{
    "authority": "https://login.microsoftonline.com/common",
    "application_client_id": "11aa1a1a-a111-1111-aa11-1aa1aa1aa1a1",
    "auth_scopes": "user.read"
}

Secrets & Config files

I’ve add a file that is not checked in using .gitignore:

example/app_config_secret.json

It can use to run the application and test authentication with Azure AD

Loading your secret config file

There are now three config files in the project to support testing:

Multiple config files added to pubspec.yaml

The original app_config.json is for development and ignores authentication.

app_config_live.json is used by the integration tests to test routing & authentication.

app_config_secret.json is used to test against my Azure AD and contains secrets that are not checked in.

You can create your own ‘app_config_secret.json’ file that points to your Azure AD service.

Microsoft Access Layer (MSAL)

Microsoft authentication library (MSAL), is not just one but a set of libraries to support web, mobile and desktop development, its purpose is to make it easy to authenticate and authorise users and applications.

I feel happier leaving this client code to Microsoft, as we can easily update the package to stay up to date with latest security patches.

MSAL uses the shared system web browser to make authentication requests and cache authenticated accounts, how it caches the account is abstracted by MSAL and we can rely on it to be the most secure method available.

With each platform having its own MSAL library I’ve decide to use the azure_ad_authentication package to abstract the platform specific implementations.

Azure Ad Authentication Package

There are a number of dart packages for MSAL authentication, I chose azure_ad_authentication because it was recently updated and has a great pub score of 140 out of 140.

The package includes native MSAL implementations for iOS, Android and the web, each require platform specific configure to work, which is detailed in the package instructions.

For iOS I completed the these steps:

Add a new keychain in Xcode:

Add a new capability to your project
Select keychain sharing
New section added to capabilities
Add new group …adalcache

Add An Entitlement for the new Keychain

Add it to the Runner.entitlements file:

<dict>
	<key>keychain-access-groups</key>
	<array>
		<string>$(AppIdentifierPrefix)com.microsoft.adalcache</string>
	</array>

Add Redirect URI

Add the application redirect URI scheme to the Info.plist file to allow the identity server to respond to the iPhone or iPad:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	...
	<key>CFBundleURLSchemes</key>
    <array>
        <string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    </array>
</dict>
</plist>

Note: URI schemes present an attack vector, so you will need to carefully consider that actions your application takes in response.

Add the query schemes

Add LSApplicationQueriesSchemes to info.plist to allow making call to Microsoft Authenticator if installed. Note that “msauthv3” scheme is needed when compiling your app with Xcode 11 and later.

...
	<key>LSApplicationQueriesSchemes</key>
	<array>
		<string>msauthv2</string>
		<string>msauthv3</string>
	</array>
</dict>
</plist>

Add the package to the project

Add the azure_ad_authentication dart package to the DigestablePrologue project :

# Azure Ad package Msal login for Android, iOS and MacOs, 
# AD refund information user and token and expiration time session
  azure_ad_authentication: ^1.0.4

Debugging Authentication Configuration Issues

I lost a bit of time to a config error because the SwiftAzureAdAuthentication plugin added by the azure_ad_authentication package was not returning the error from MSAL, just a text message “CONFIG_ERROR”_:

create the application and return it
        //MSALPublicClientApplication(configuration: config)
        if let application = try? MSALPublicClientApplication(configuration: config)
        {
            // application.validateAuthority = false
            return application
        }else{
            
            result(FlutterError(code: "CONFIG_ERROR", message: "Unable to create MSALPublicClientApplication", details: nil))
            return nil
        }

I found this plugin code by opening Xcode and searching for “MSALPublicClientApplication”, which is deeply nested:

Deeply nested plugin source code

But it can be found, amended it and debugged in Xcode, so I added the following code and a break point:

do{
    let application = try MSALPublicClientApplication(configuration: config)
  } catch {       
    print(error)
  }

Which allowed me to surface the error, a simple dyslexic spelling “simub” instead of “simbu”:

0]	(null)	"MSALErrorDescriptionKey" : "The required app scheme \"msauth.com.simub.digestableprologue\" is not registered in the app's info.plist file. Please add \"msauth.com.simub.digestableprologue\" into Info.plist under CFBundleURLSchemes without any whitespaces and make sure that redirectURi \"msauth.com.simub.digestableprologue://auth\" is register in the portal for your app."

MSAL Authentication Service

The environment in the app_config_.json file:

"environment": "live",

Is used by the authentication service provider to inject the per environment service:

AuthenticationServiceStateNotifier selectAuthenticationServiceByEnvironment() {
  var environment = GlobalEnvironmentValues.instance.environment;

  AuthenticationService authenticationService = environment == Environments.live
      ? MsalAuthenticationService()
      : StubbedAuthenticationService();

  return AuthenticationServiceStateNotifier(authenticationService);
}

The AD config values are loaded when the application is started from the same app_config_.json as GlobalEnvironmentValues and the MSAL Authentication Service uses them to initialise the iOS MSAL library:

return await AzureAdAuthentication.createPublicClientApplication(
        clientId: GlobalEnvironmentValues.instance.applicationClientId,
        authority: GlobalEnvironmentValues.instance.authority);

When

(authenticationServiceProvider).signIn()

is called the iOS MSAL plugin method

aquireToken()

is called via the azure_ad_authentication package to start the authentication process, it then slides up a web view to complete sign in with the user.

Redirect URL

The iOS redirect URL in info.plist

msauth.com.simbu.digestableprologue

Needs to match the redirect specified in the Azure app registration:

Azure app registration redirect

Sound & Vision

Packages

Links

Flutter
Programming
Mobile
Mobile App Development
API
Recommended from ReadMedium