Skip to content

Leveraging the broker on iOS and Android

Travis Walker edited this page Mar 6, 2020 · 17 revisions

Why use brokers on Xamarin.iOS and Xamarin.Android applications?

On Android and iOS, brokers enable:

  • Single Sign On (SSO). Your users won't need to sign-in to each application.
  • Device identification. By accessing the device certificate which was created on the device when it was workplace joined.
  • Application identification verification. When an application calls the broker, it passes its redirect url, and the broker verifies it.

To enable one of these features, application developers need to use the WithBroker() parameter when calling the PublicClientApplicationBuilder.CreateApplication method. .WithBroker() is set to true by default. Developers will also need to follow the steps below for iOS or Android applications.

Brokered Authentication for iOS

Follow the steps below to enable your Xamarin.iOS app to talk with the Microsoft Authenticator app.

If you are targeting iOS 13, please read this important section on MSAL.NET and broker auth support for iOS 13

Step One: Enable broker support

Broker support is enabled on a per-PublicClientApplication basis. It is disabled by default. You must use the WithBroker() parameter (set to true by default) when creating the PublicClientApplication through the PublicClientApplicationBuilder.

var app = PublicClientApplicationBuilder
                .Create(ClientId)
                .WithBroker()
                .WithReplyUri(redirectUriOnIos) // $"msauth.{Bundle.Id}://auth" (see step 6 below)
                .Build();

Step Two: Enable keychain access

To enable keychain access, your application must have a keychain access group. You can set your keychain access group by using the WithIosKeychainSecurityGroup() api when creating your application as shown below:

var builder = PublicClientApplicationBuilder
     .Create(ClientId)
      
     .WithIosKeychainSecurityGroup("com.microsoft.adalcache")
     .Build();

The Entitlements.plist should be updated to look like the following:

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

Learn more on enabling keychain access.

Step Three: Update AppDelegate to handle the callback

When MSAL.NET calls the broker, the broker will, in turn, call back to your application through the OpenUrl method of the AppDelegate class. Since MSAL will wait for the response from the broker, your application needs to cooperate to call MSAL.NET back. You do this by updating the AppDelegate.cs file to override the below method.

public override bool OpenUrl(UIApplication app, NSUrl url, 
                             string sourceApplication,
                             NSObject annotation)
{
    if (AuthenticationContinuationHelper.IsBrokerResponse(sourceApplication))
    {
         AuthenticationContinuationHelper.SetBrokerContinuationEventArgs(url);
         return true;
    }
    
    else if (!AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url))
    {	            
         return false;	              
    }
	
    return true;	 
}	        

This method is invoked every time the application is launched and is used as an opportunity to process the response from the broker and complete the authentication process initiated by MSAL.NET.

Step Four: Set a UIViewController()

Still in AppDelegate.cs, you will need to set an object window. Normally, with Xamarin iOS, you do not need to set the object window, but in order to send and receive responses from broker, you will need an object window.

To do this, you will need to do two things.

  1. In AppDelegate.cs, set the App.RootViewController to a new UIViewController(). This will make sure there is a UIViewController with the call to the broker. If it is not set correctly, you may get this error: "uiviewcontroller_required_for_ios_broker":"UIViewController is null, so MSAL.NET cannot invoke the iOS broker. See https://aka.ms/msal-net-ios-broker"
  2. On the AcquireTokenInteractive call, use the .WithParentActivityOrWindow(App.RootViewController) and pass in the reference to the object window you will use.

For example:

In App.cs:

   public static object RootViewController { get; set; }

In AppDelegate.cs:

   LoadApplication(new App());
   App.RootViewController = new UIViewController();

In the Acquire Token call:

result = await app.AcquireTokenInteractive(scopes)
             .WithParentActivityOrWindow(App.RootViewController)
             .ExecuteAsync();

Step Five: Register a URL Scheme

MSAL.NET uses URLs to invoke the broker and then return the broker response back to your app. To finish the round trip, you need to register a URL scheme for your app in the Info.plist file.

The CFBundleURLSchemes name must include msauth. as a prefix, followed by your CFBundleURLName.

$"msauth.(BundleId)"

For example: msauth.com.yourcompany.xforms

Note This will become part of the RedirectUri used for uniquely identifying your app when receiving the response from the broker.

 <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLName</key>
        <string>com.yourcompany.xforms</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>msauth.com.yourcompany.xforms</string>
        </array>
      </dict>
    </array>

Step Six: LSApplicationQueriesSchemes

MSAL uses –canOpenURL: to check if the broker is installed on the device. In iOS 9, Apple locked down what schemes an application can query for.

Add msauthv2 to the LSApplicationQueriesSchemes section of the Info.plist file.

<key>LSApplicationQueriesSchemes</key>
    <array>
      <string>msauthv2</string>
      <string>msauthv3</string>
    </array>

Step Seven: Register your RedirectUri in the application portal

Using the broker adds an extra requirement on your redirectUri. The redirectUri must have the following format:

$"msauth.{BundleId}://auth"

For example:

public static string redirectUriOnIos = "msauth.com.yourcompany.XForms://auth"; 

You'll notice the RedirectUri matches the CFBundleURLSchemes name you included in the Info.plist file.

Step Seven: make sure the redirect URI is registered with your app

This Redirect URI needs to be registered on the app registration portal (https://portal.azure.com) as a valid redirect URI for your application.

Note that there is a new experience in the app registration portal to help you compute the brokered reply URI from the bundle ID:

  1. In the app registration choose Authentication and selection Try-out the new experience image

  2. Select Add platform image

  3. When the list of platforms is supported, select iOS image

  4. Enter your bundle ID as requested, and then press Register image

  5. The redirect URI is computed for you. image

Brokered Authentication for Android

Step One: Enable broker support

Broker support is enabled on a per-PublicClientApplication basis. It is disabled by default. You must use the WithBroker() parameter (set to true by default) when creating the PublicClientApplication through the PublicClientApplicationBuilder.

var app = PublicClientApplicationBuilder
                .Create(ClientId)
                .WithBroker()
                .WithReplyUri(redirectUriOnAndroid) //(see step 4 below)
                .Build();

Step Two: Update AppDelegate to handle the callback

When MSAL.NET calls the broker, the broker will, in turn, call back to your application with the OnActivityResult() method. Since MSAL will wait for the response from the broker, your application needs to route the result to MSAL.NET. This can be achieved by routing the result to the SetAuthenticationContinuationEventArgs(int requestCode, Result resultCode, Intent data) by overriding the OnActivityResult() method as shown below

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);
            AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
        }

This method is invoked every time the broker application is launched and is used as an opportunity to process the response from the broker and complete the authentication process initiated by MSAL.NET.

Step Three: Set an Activity

For brokered authentication to work you will need to set an activity so that MSAL can send and receive the response from broker.

To do this, you will need to provide the activity(usually the MainActivity) to the WithParentActivityOrWindow(object parent) as the parent object.

For example:

In the Acquire Token call:

result = await app.AcquireTokenInteractive(scopes)
             .WithParentActivityOrWindow((Activity)context))
             .ExecuteAsync();

Step Four: Register your RedirectUri in the application portal

MSAL uses URLs to invoke the broker and then return back to your app. To finish that round trip you need to register a URL scheme for your app. This Redirect URI needs to be registered on the app registration portal (https://portal.azure.com) as a valid redirect URI for your application.

The redirect URI needed for your application is dependent on the certificate used to sign the APK.

Example: msauth://com.microsoft.xforms.testApp/hgbUYHVBYUTvuvT&Y6tr554365466=

The last part of the URI, hgbUYHVBYUTvuvT&Y6tr554365466=, is the signature that the APK is signed with, base64 encoded. However, during the development phase of your application using Visual Studio, if you are debugging your code without signing the apk with a specific certificate, Visual Studio will sign the apk for you for debugging purposes, giving the APK a unique signature for the machine that it is built on. Thus, each time you build your app on a different machine, you will need to update the redirect URI in the application’s code and the application’s registration in the azure portal in order to authenticate with MSAL.

While debugging, you may encounter an MSAL exception (or log message) stating the redirect URI provided is incorrect. This exception will also provide you with the redirect URI that you should be using with the current machine you are debugging on. You can use this redirect URI to continue developing for the time being.

Once you are ready to finalize your code, be sure to update the redirect URI in the code and on the application's registration in the azure portal to use the signature of the certificate you will be signing the APK with.

The following methods demonstrate how you can get the current redirect URI for the APK

        private string GetRedirectUriForBroker()
        {
            string packageName = Application.Context.PackageName;
            string signatureDigest = this.GetCurrentSignatureForPackage(packageName);
            if (!string.IsNullOrEmpty(signatureDigest))
            {
                return string.Format(CultureInfo.InvariantCulture, "{0}://{1}/{2}", RedirectUriScheme,
                    packageName.ToLowerInvariant(), signatureDigest);
            }

            return string.Empty;
        }

        private string GetCurrentSignatureForPackage(string packageName)
        {
            try
            {
                PackageInfo info = Application.Context.PackageManager.GetPackageInfo(packageName,
                    PackageInfoFlags.Signatures);
                if (info != null && info.Signatures != null && info.Signatures.Count > 0)
                {
                    // First available signature. Applications can be signed with multiple signatures.
                    // The order of Signatures is not guaranteed.
                    Signature signature = info.Signatures[0];
                    MessageDigest md = MessageDigest.GetInstance("SHA");
                    md.Update(signature.ToByteArray());
                    return Convert.ToBase64String(md.Digest(), Base64FormattingOptions.None);
                    // Server side needs to register all other tags. ADAL will
                    // send one of them.
                }
            }
            catch (Exception ex)
            {
                //Handle Exception
            }

            return null;
        }

You also have the option of acquiring the signature for your package by using the keytool with the following commands:

For Windows: keytool.exe -list -v -keystore "%LocalAppData%\Xamarin\Mono for Android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

For Mac: keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

Getting started with MSAL.NET

Acquiring tokens

Desktop/Mobile apps

Web Apps / Web APIs / daemon apps

Advanced topics

News

FAQ

Other resources

Clone this wiki locally