Setup Xamarin iOS to Login to Azure ADAL and Sharepoint Online

misc1This project takes a lot from this and makes changes for the new API (you must register your SharePoint application with Azure AD).  This document sets up Azure AD for Sharepoint Online.

When using the ADAL package on the Xamarin iPhone emulator, it requires quite a process to get up and running.  Installing ADAL requires the NuGet Package  “Microsoft.IdentityModel.Clients.ActiveDirectory”. Once that’s installed, you must create an authenticator service to assist with authenticating.

Here’s the interface which is kept in the Shared Library:

public interface IAuthenticator
    {
        string LoggedInEmail { get; }
        AuthenticationResult Result { get; }
        void SignOut();
        bool IsAuthenticated();
        Task<AuthenticationResult> Authenticate();
        Task CheckUpdateToken();
    }

Here are the authentication settings (once again, it’s kept in the shared library).  The settings are set when the user initially sets up the Azure AD Application:

 public interface IAuthenticateSettings
    {
        string ClientId {get;}
        string Tenant { get; }
        string Authority { get; }
        string ReturnUri { get; }
        string GraphResourceUri { get; }
        string SharePointResource { get; }
    }

    public class AuthenticateSettings : IAuthenticateSettings
    {
        public string ClientId { get; private set; } = "clientID";
        public string Tenant { get; private set; } = "<tenant-name>.onmicrosoft.com"

        public string Authority { get; private set; } = String.Format("https://login.microsoftonline.com/{0}", "<tenant>");

	public string ReturnUri { get; private set; }  = "Return URI";
	public string GraphResourceUri { get; private set; } = "https://graph.windows.net";
	public string SharePointResource  { get; private set; } = "https://your sharepoint site.sharepoint.com";
	}

This is how the implementation looks in the iOS project:

[assembly: Dependency(typeof(AccordCarton.iOS.Services.Authenticator))]
namespace AccordCarton.iOS.Services
{
public class Authenticator : IAuthenticator
    {
        private readonly IAuthenticateSettings _authenticateSettings;

        public Authenticator(IAuthenticateSettings authenticateSettin)
        {
            _authenticateSettings = authenticateSettings;
        }

        public AuthenticationResult Result { get; private set; }
        public string LoggedInEmail
        {
            get
            {
                return Result == null ? string.Empty : Result.UserInfo.DisplayableId;
            }
        }

        public async Task<AuthenticationResult> Authenticate()
        {
            var authContext = new AuthenticationContext(_authenticateSettings.Authority);
            if (authContext.TokenCache.ReadItems().Any())
                authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);

            var controller = UIApplication.SharedApplication.KeyWindow.RootViewController;
            var uri = new Uri(_authenticateSettings.ReturnUri);
            var platformParams = new PlatformParameters(controller);
            var authResult = await authContext.AcquireTokenAsync(_authenticateSettings.SharePointResource,
                                                                 _authenticateSettings.ClientId, uri, platformParams);
            Result = authResult;
            return authResult;
        }

        public bool IsAuthenticated()
        {
            var authContext = new AuthenticationContext(_authenticateSettings.Authority);
            var isAuthenticated =  authContext.TokenCache.ReadItems().Any();
            return isAuthenticated;
        }

        public void SignOut()
        {
            var authContext = new AuthenticationContext(_authenticateSettings.Authority);
            authContext.TokenCache.Clear();
        }

        public async Task CheckUpdateToken()
        {
            if (Result.ExpiresOn - DateTime.Now.ToUniversalTime() <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span><span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>< TimeSpan.FromMinutes(5)){
                await Authenticate();
            }
        }
    }
}

Once this is up and running, you need to get an instance of the IAuthenticator and call Authenticate.  This will allow you to authenticate through the Azure ADAL login screen:

adal-login

From there, the system retrieves a token and that token can be used when performing application calls (in this case, it is sharepoint):

public class ActionItemService: IActionItemService
    {
        private readonly IAuthenticator _authenticator;

        public ActionItemService(IAuthenticator authenticator)
        {
           _authenticator = authenticator.
        }       	

protected void SetUriAndHeaders(HttpClient client)
		{
			client.BaseAddress = new Uri(SharePointBaseAddress);
			client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _authenticator.Result.AccessToken);
			client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json;odata=verbose");
			client.DefaultRequestHeaders.Accept
			.Add(new <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>MediaTypeWithQualityHeaderValue("application/json"));
		}

        public async Task<List<ActionItem>> GetOpenActionItemsAsync()
        {
            await _authenticator.CheckUpdateToken();

            using (var client = new HttpClient())
            {
                SetUriAndHeaders(client);
                var response = await client.GetAsync("_api/web/lists/GetByTitle('ActionItems')/Items?$filter=Status eq'Open'");
				response.EnsureSuccessStatusCode();
                var contents = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<SpResponseItem<ActionItem>>(contents).Value;
            }
        }
}

Now you can communicate with Sharepoint Online using the Sharepoint API.

One thing to note is that when logging in on the iOS emulator, you must login every time that you start the application, but on the real device, you only need to login once.

By default, the tokens are good for 1 hour.  You’ll need to call the login function to refresh the token.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s