Put Some Azure Active Directory in Xamarin.Forms

Mayur Tendulkar

The Azure Active Directory Authentication Library (aka ADAL) makes authentication with Azure Active Directory a breeze. We’ve already covered usage of ADAL in various posts on authenticating with Active Directory, adding storage, and adding collaboration (SharePoint) to your mobile apps. azure-active-directoryADAL is available for various platforms and supports Xamarin.Android, Xamarin.iOS, and Windows Phone. It’s easy to integrate ADAL into these projects by adding a NuGet package. Although ADAL hasn’t released a specific Package for Xamarin.Forms, there have been many questions in the Xamarin forums and on StackOverflow about how to use ADAL in a Xamarin.Forms app.

Recently, Vittorio Bertocci, Principal Program Manager at Microsoft, posted a blog about integrating ADAL into Xamarin.Forms apps using a PageRenderer. In this post, I’ll be sharing another way to integrate ADAL into Xamarin.Forms apps using Dependency Service, which is available in Xamarin.Forms.

 

Step 1: Create a Xamarin.Forms App

Create a Xamarin.Forms app in Xamarin Studio or Visual Studio. If you create this project with Visual Studio, it will create four projects: PCL, Android, iOS, and Windows Phone. In this solution, the Windows Phone project created with Xamarin.Forms uses the Silverlight framework, which has different requirements for implementing ADAL than iOS, Android, or Windows Runtime apps. So let’s add a Windows Phone 8.1 project, for which we’ll use the new Windows Runtime framework by following the steps in the documentation. Follow the guide and make sure your project structure looks similar to my solution below:

ADAL-In-Xamarin-Forms-01

Step 2: Add NuGet Package References

For each project (excluding Windows Phone 8.0 Silverlight), add an ADAL NuGet package (currently pre-release). The same NuGet package with the same version should get added to each platform project.

ADAL-In-Xamarin-Forms-02

Step 3: Create IAuthenticator Interface

In your PCL, add a new interface with the Authenticate method. It should return AuthenticateResult from ADAL, which contains the AccessToken and other details that are required for further API calls.

public interface IAuthenticator
{
  Task<AuthenticationResult> Authenticate(string authority, string resource, string clientId, string returnUri);
}

Step 4: Create IAuthenticator Implementations

The Authenticate method body is almost the same in each platform. The only change that occurs is different parameters for PlatformParameters, which governs the authentication flow and maintains the context of the app.

Let’s review the implementations one at a time.

Android Implementation

PlatformParameters needs an Activity in Android, and in Xamarin.Forms you can cast Forms.Context to grab the main Activity. The entire implementation in your Android project would look like this:

[assembly: Dependency(typeof(ADALForForms.Droid.Helper.Authenticator))]
namespace ADALForForms.Droid.Helper
{
  class Authenticator : IAuthenticator
  {
    public async Task<AuthenticationResult> Authenticate(string authority, string resource, string clientId, string returnUri)
    {
      var authContext = new AuthenticationContext(authority);
      if (authContext.TokenCache.ReadItems().Any())
        authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);

      var uri = new Uri(returnUri);
      var platformParams = new PlatformParameters((Activity)Forms.Context);
      var authResult = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
      return authResult;
    }
  }
}

Apart from this, you’ll also need to override the OnActivityResult method in the MainActivity.cs file, which will continue the authentication flow.

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

iOS Implementation

For iOS, PlatformParameters accepts a UIViewController to maintain the context. We can set RootViewController to use it as context, so the implementation on iOS should be as follows:

[assembly: Dependency(typeof(ADALForForms.iOS.Helper.Authenticator))]
namespace ADALForForms.iOS.Helper
{
  class Authenticator : IAuthenticator
  {
    public async Task<AuthenticationResult> Authenticate(string authority, string resource, string clientId, string returnUri)
    {
      var authContext = new AuthenticationContext(authority);
      if (authContext.TokenCache.ReadItems().Any())
        authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);

      var controller = UIApplication.SharedApplication.KeyWindow.RootViewController;
      var uri = new Uri(returnUri);
      var platformParams = new PlatformParameters(controller);
      var authResult = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
      return authResult;
    }
  }
}

In the case of iOS, we don’t need to override/implement any separate method to continue the authentication flow. We should get authResult back whenever the authentication flow completes.

Windows Phone Implementation

PlatformParameters doesn’t need any parameter as such for the Windows Phone app, so we’ll use the following code to allow us to authenticate with AD:


[assembly: Dependency(typeof(ADALForForms.Phone.Helper.Authenticator))]
namespace ADALForForms.Phone.Helper
{
  class Authenticator : IAuthenticator
  {
    public async Task<AuthenticationResult> Authenticate(string authority, string resource, string clientId, string returnUri)
    {
      var authContext = new AuthenticationContext(authority);
      if (authContext.TokenCache.ReadItems().Any())
        authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);

      var uri = new Uri(returnUri);
      var platformParams = new PlatformParameters();
      var authResult = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
      return authResult;
    }
  }
}

Just like Android, Windows Phone needs to handle the continuation after login. This can be done by overriding the OnActivated method in the App.xaml.cs file and calling back to the WebAuthenticationBrokerContinuationHelper.


protected override void OnActivated(IActivatedEventArgs args)
{
#if WINDOWS_PHONE_APP
  if (args is IWebAuthenticationBrokerContinuationEventArgs)
  {
    WebAuthenticationBrokerContinuationHelper.SetWebAuthenticationBrokerContinuationEventArgs(args as IWebAuthenticationBrokerContinuationEventArgs);
  }
#endif
  base.OnActivated(args);
}

Step 5: Call Authenticate() in the Apps

Now, we need to call the Authenticate method. Let’s add a new HomePage with a button, which should call the Authenticate method on its click event. Before this, let’s declare some variables that are required for authentication. To do so, add a new XAML Page and declare your variables for ADAL.

public static string clientId = "your-client-id";
public static string authority = "https://login.windows.net/common";
public static string returnUri = "your-redirct-uri";
private const string graphResourceUri = "https://graph.windows.net";
private AuthenticationResult authResult = null;

Now, we can use the Dependency Service from Xamarin.Forms to locate the Authenticate method in each platform and execute it.

private async void Button_OnClicked(object sender, EventArgs e)
{
 var auth = DependencyService.Get<IAuthenticator>();
 var data = await auth.Authenticate(authority, graphResourceUri, clientId, returnUri);
 var userName = data.UserInfo.GivenName + " " + data.UserInfo.FamilyName;
 await DisplayAlert("Token", userName, "Ok", "Cancel");
}

Here, you should have results in the authResult variable. You can use the Access Token from authResult to call any APIs that are secured by Azure Active Directory, e.g., Office 365 and Graph.

ADAL-In-Xamarin-Forms-Last-Image

Note: ADAL used in this blog post is in preview mode. There may be changes by the time it is released.

You can download the sample created for this post, update your credentials (e.g. Client Id and Redirect URI), and test the app from GitHub

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Dino Buljubasic 0

    @MayurTendulkar How do you handle situation when user is prompted to enter user email, then clicks Next button, new screen shows asking for password.  If on Android, user now rotates device, he will be returned back to screen asking for user email (which he just provided a second ago).  Even worse than returning back to this screen, the user email entered before is lost and need to be reentered again.
    See details here https://forums.xamarin.com/discussion/160543/xamarin-forms-azure-aad-login-page-looses-entered-user-name-on-device-orientation#latest
    Rotating device should not reprompt again for user email when trying to sign in using ADAL.  it should simply continue where it was before device was rotated and let user finish entering password.

Feedback usabilla icon