Inter-App Communications in Xamarin.iOS and Why OpenUrl Freezes for 10+ sec

Inter-App Communications

Mobile apps are meant to communicate using multiple channels, but the most popular, recommended, and widely used is using Scheme Uri. If you have not used Scheme URI then you should consider adding them to your app, it takes less than a minute to add support to your app, and it provides you a great way to get users to your app.

Setting the Stage

One scenario that I had was App A was launching App B and querying data, App B was in turn looking up the request, and returning data to App A. This is a common practice and can be seen in the diagram below.

Scheme uri ios

Scheme uri ios

The Investigation

The problem here was that App B was freezing for up to 10+ sec before returning the result to App A. At first, I thought that this might be because the app initialisation or the data lookup taking long time, so I added diagnostic trace statements like below to time the operation and see where the time is spent.

public class AppDelegate
{
	...
	
	public override bool FinishedLaunching(UIApplication app, NSDictionary options)
	{
		Console.WriteLine("FinishedLaunching started: " + DateTime.Now.ToString("F"));

		...
		
		Console.WriteLine("FinishedLaunching complete: " + DateTime.Now.ToString("F"));
	}

	public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
	{
		Console.WriteLine("OpenUrl started: " + DateTime.Now.ToString("F"));

		...
		

		Console.WriteLine("OpenUrl complete: " + DateTime.Now.ToString("F"));
	}
}

I found that my app was starting in less than 1 Sec, which is quite impressive, and I am very happy about 🙂 but the problem was in returning the data to the launching app (App A). The traces were like these:

Launch Services application launch failed - timeout waiting - Trace logs

Launch Services application launch failed – timeout waiting – Trace logs

This is telling me that App B was not able to launch App A to return back the data, which was quite surprising. I found that if you move that code to your pages/viewControllers things work fine. I thought that this was a bizarre situation, then I found this StackOverflow post, which explained the problem.

The Solution

Apparently, the iOS was having a race-condition like in trying to launch an app while the app itself was not fully launched. So the suggested solution was to add some delay or run it on another thread. Running the launch of App A on another thread would not work as it needs to be on the mainUiThread, so here is the solution I came up with:


public class AppDelegate
{
	...
	
	public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
	{
		// handle opening url and look up data

		...

		Task.Delay(500).ContinueWith(_ => 
				{									
					this.InvokeOnMainThread( () => 
					{			
						var uri = NSUrl.FromString(callbackUri);
						UIApplication.SharedApplication.OpenUrl(uri);
									
					});

				});

		return true;
		
	}
}

: LaunchServices: application launch failed – timeout waiting for launch.

This works like a charm :). First, we got rid off the launch service error (shown above). Second, App B is now returning the results to App A in less than 3 sec. If App B is in the background then it would return the data in less than 1 sec. Otherwise, it would take up to 3 sec to return the data. yayyy 🙂

Any device, any platform, one Microsoft

Only a few years ago you’d have been hard pressed to have mentioned the following four words in a single blog post where you weren’t arguing for / against a way of doing things: Microsoft, iOS, Android and development.

Unless you’ve been living under a rock you will no doubt have seen Microsoft’s announcement on their intent to acquire Xamarin, a business very much about cross-platform application development.

For those of us working in this space this has really been a case of
“what took you so long?” rather than “why?”.

So why should you care? Let me explore this for you…

Please note I don’t have any more insight than you in what the acquisition means. However, based on Kloud’s experience building real business and consumer solutions using Xamarin, I’m going to give you what I think it means to those of us who develop platform-specific applications.

Some background

Microsoft has been working independently of Xamarin to produce its own toolchain for cross-platform application development for the past few years. You’ll note the majority of these are about enabling solutions on any platform which, again, is very different to Microsoft of years gone by.

Portable Class Libraries (PCLs)
A great enabler that unlocks transportable .Net code. These are a big part of the success of Xamarin as they have allowed popular .Net libraries to be made available for use off-Windows, even prior to Microsoft open sourcing the .Net Framework.
https://msdn.microsoft.com/library/gg597391(v=vs.100).aspx

Visual Studio Tools for Apache Cordova
Cordova is a great tool for facilitating rapid delivery of cross-platform applications where you are prepared to forgo some aspects of native capability. If you have a bunch of web-centric developers then the foundation components for Cordova will seem very familiar. The Visual Studio tooling is some of the best you’ll find and is actively maintained.
https://www.visualstudio.com/en-us/features/cordova-vs.aspx
Azure – Mobile Apps, Notification Hubs & Mobile Engagement
Probably the most mature mobile back-end platform about. Integration with APNS and GCM just works and the quick-starts are a great way to dip your toes into mobile application development. The addition of Capptain in 2014 (now Mobile Engagement) bolstered this offering.
https://azure.microsoft.com/en-us/services/app-service/mobile/

Windows Bridge for iOS (formerly Project Islandwood)
There’s no denying iOS and Android are leading platforms, so how do you allow existing applications to run on Windows? You use a Bridge.
https://dev.windows.com/en-us/bridges/ios
Windows Bridge for Android (formerly Project Astoria)
This one’s an interesting one. Unlike the iOS Bridge, Astoria isn’t moving ahead. What happens here? We’ll have to wait and see, though no doubt Xamarin plays a part.
http://www.windowscentral.com/microsoft-officially-cancels-project-astoria-bridge-porting-android-apps-windows-10-mobile

So, C# is the future?

If you’re an experienced iOS and Android developers using Objective-C, Swift or Java you don’t need to drop everything you’re doing and pick up C#.

Chances are you aren’t particularly interested in it… but… you are in an extremely good position to pick up and run with development in this space using Xamarin and C#. Also, you can always import those native libraries you are already using anyway if you find a gap (which is unlikely).

C#’s syntax should not hold a lot of surprises for many iOS and Android developers, and as you already know a lot about the UI constructs on each platform you’re ahead of the pack. While it’s true that a C# developer can quickly deliver solutions using Xamarin, the nearer you get to the UI experience the more platform-specific knowledge you require, even if you leverage something like Xamarin.Forms.

APIs ahoy!

Existing C# developers also get benefits here as they can quickly build cross-platform solutions and only leverage specific skills for certain aspects of the applications (typically the UI). Write it once, deploy on any platform (where have I heard that before???) really comes true here in many cases.

Many great apps are let down by terrible APIs, either through poor performance or security. Imagine a world where your API implementation experts can also write the client libraries that will consume those APIs? C# and Xamarin unlocks this scenario.

But I already have an app for X

When I spoke about Xamarin at TechEd Australia 2013 the number one question I got after the session was along the lines of “I already have an native app on X, why would I use Xamarin?”

This is a fair question and to suggest that you simply re-implement the application in C# with Xamarin is not the answer you want to hear.

No doubt, though, you are eyeing at least one other major mobile platform in the market and wondering how your existing application can reach that platform.

You have two choices: go native or go cross-platform.

This is your sweet spot – go cross-platform. Eventually you will find a smaller incremental change will deliver you the same cross-platform application on your existing platform of choice.

Yeah, but a native app’s so much better

In the smallest of circumstances you may be right. As I said, Kloud has successfully built and deployed heavily used enterprise and consumer applications that I would dare you to pick as having been developed using Xamarin.

Xamarin has spent a lot of time documenting real-world use of their technology that I’d recommend you go and digest.

But it’s Microsoft!

Yes it is.

The one that has the leading productivity apps on iOS and Android platforms, supports Docker, has its own OpenSSH port, open sourced the .Net Framework, its JavaScript engine and works in the open on GitHub.

Microsoft’s strength has always been its understanding of the developer and the tools they need to do their work. Now with Xamarin you get this benefit regardless of your platform of choice.

Happy Days! 🙂

Taking Advantage of The (iOS 9) Universal Links on Xamarin iOS apps

What is Scheme URI?

In the context of mobile apps, Scheme URIs are used for communicating between mobile apps. Mobile developers can register a unique URI for each app in the application manifest (info.plist). The operating system would then use that to launch your application once the user clicks on a link that matches your uri. For instance, I could have my-cool-app:// as my scheme uri. I could then generate links (should start with my-cool-app://) to send in my email to my app’s users and once clicked, my app will be launched. These have become standard and they are widely supported on iOS, Windows, and Android.

What is Universal Links?

Universal Links is a new feature that was introduced by Apple in iOS 9. The idea is instead of registering a scheme Uri, you could use your own website domain name (which is inherently unique) and associate this domain name with your mobile app. Once the user clicks on a http/https link that links to your domain name, iOS would then launch your mobile application instead of opening the link in Safari. More details about Universal Links could be found in in this WWDC session and Apple’s official documentation.

Why Do we need Universal Links?

If you have used Scheme URIs before to open your mobile apps, you would know the pain of trying to keep your links valid to open your app (when installed) and fallback to the web links when your app is not installed. You would also know this was not a simple task, and there was no guarantee that this would work exactly the way you want. Therefore, Apple has introduced Universal Links, which is great. Imagine how many times you get a URL link via email and you click it to end up in a web browser asking you for username and password. Most people do not remember their accounts (at least not for all accounts), or they want to see this content on the mobile app instead of Safari. This new feature (Universal Links) solves this problem.

How Can we Enable Universal Links?

To enable Universal Links, you need to follow the following steps:

1. Enable “Associated Domains” on your Application Id (in Apple Developer portal).

Enable Associated Domains in your App Identifier settings - Apple Dev Portal

Enable Associated Domains in your App Identifier settings – Apple Dev Portal

2. Create an apple-app-site-association file on your domain. This is just a text file that contains a JSON object to describe your universal links. You could associate multiple link paths with multiple apps. Notice that your app id needs to have your full app identifier (TeamName.Appid). I’ve shown a sample of the JSON content below:

    {
        “applinks”: {
            “apps”: [],
            “details”: [
                {
                    “appID”: “ABC-Team-Id.com.my.bundle.id“,
                    “paths”: [ “/”, “*” ]
                }
            ]
        }
    }

This file needs to be served over HTTPS and have no file extension – it must be named “apple-app-site-association”. Apple will try to retrieve this file from your domain before it launches your app for the first time. This is to verify the authenticity of your domain ownership before starting the app. If you are hosting this file on an Azure Web App, you might also need to add a static content mapping in your web.config.

The bottom line is you need to make sure that you can navigate to this file as https://your-domain.com/apple-app-site-association. There is also a small app that helps you verify your Apple association file, you could find it here. Do not worry about the last 2 errors that it displays concerning signing your file. I have my Universal Links work without signing the association file, but this web page is still good to verify other aspects of the association file.

3. Add the Universal Links Entitlement to your info.plist. This can be done very simply by navigating to your Entitlements.plist and add the new applinks as follows:

Applinks in Entitlments-plist file

Applinks in Entitlments-plist file

4. Regenerate your provisioning profiles. This is very important since we changed our app id entitlements. If you don’t do this you will get an error message when trying to build the app saying that you have entitlements that are not permitted by your provisioning profile.

5. OPTIONAL: Override ContinueUserActivity method in your app’s delegate to capture the URL link that the user clicked on. This is necessary when you want to take the user into the particular screen in your application. For instance, if the user clicked on a link to view a product on your website, you could capture the link in this method and once your app opens up, view the details of that product on your mobile app.

public override bool ContinueUserActivity (UIApplication application, 
     NSUserActivity userActivity, 
     UIApplicationRestorationHandler completionHandler)
{
	Console.WriteLine ("ContinueUserActivity method has been called...");
	// you can get the url that the user clicked on here.		
	return true;
}

Once all the above is done, you can build and deploy to your device. I have tested my implementation by creating a link to my associated domain and sent it via email to the device. When I click on the link, I get redirected to my app directly (without going through Safari).

Applinks in the mobile app - screenshot

Applinks in the mobile app – screenshot

Notice that Apple give the user the option to stay on my app, go directly the browser (upper right link) or go back to the email that launched my app. I really like this design because it keeps the user in charge. Also, there are few posts that suggest once the user taps on the link to go to the browser, Apple would then bypass your app for this link and take the user directly to the website in the future. I have not verified this but you could find the details on this Stackoverflow post.

How about devices that are still using older versions of iOS?

What we have seen above is very cool stuff and I have been hoping for this for years. However, this only solves the problem on a subset of devices. Remember there are still lots of devices out there that are not using iOS 9. If you are like me and are required to support iPhone 4, then you need to have a fallback mechanism for these devices. For this scenario, we could have simple JavaScript code that helps us redirect to our mobile app, if this redirection fails, then we assume that the app is not installed and we redirect the user to our web URL. A sample of this is below, and more details can be found on Stackoverflow:


// this could needs to sit in your website page
setTimeout(function() {
  window.location = "http://my-domain-app"; // or your could put  link to your app on iTunes
}, 25);

// If "my-cool-app://" is installed the app will launch immediately and the above
// timer won't fire. If it's not installed, you'll get an ugly "Cannot Open Page"
// dialogue prior to the App Store application launching
window.location = "my-cool-app://";

Future-Proofing

It will be very interesting to see how Apple will use this to integrate apps more with the web. Apple has already done a great work in terms of search and user activity that is bridging the gap between web and native apps. Universal Links is another step in the right direction.

How about Android?

Although most of the contents of this post is related to iOS, Android’s implementation is quite similar. Google introduced this in Android M and you can read more about it on the Android developer documentation site.

Solving self signed certificate blocking by inspecting web requests using Xamarin iOS

In iOS 9 Apple have turned on App Transport Security (ATS) as default. So if your iOS application is connecting to an insecure url resource then you’re out of luck as it will be blocked, an example of the most likely culprit is viewing a webpage without SSL encryption.

With the current application I’m working on I ran into trouble whilst loading a dev resource only to find it was using a self signed certificate and being blocked by the OS. I also had a requirement to inspect an Ajax web request and the WebView ShouldStartLoad delegate was not receiving these request callbacks.

First things first, if your applications requests are being blocked you will see something like:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

The best way to resolve this issue is to ensure all resources are securely protected in the correct way, and therefore your application, and users data, is secure!

But this is not always possible!  And if you’re like me then you have no choice but to step around the default ATS setting.

Quick, change the Info.plist!

To resolve a problem with a blocked resource you can turn off ATS for you application with a single entry in your Info.plist file. Whilst this is the simplest and quickest approach, my advice would be to avoid doing this. Yes, you may just be making the change for a quick test or prototype app, but it’s easy to forget you made the change and before you know it you’ve released an insecure app to your users.

My advice is to turn off ATS for the only resources you trust. In my case a single domain.

This can be achieved by adding the following into your Info.plist file:

<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSExceptionDomains</key>
		<dict>
			<key>[ENTER YOUR BASE URL HERE]</key>
			<dict>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSAllowsArbitraryLoads</key>
				<true/>
			</dict>
		</dict>
	</dict>

Spying on all requests

iOS is no longer blocking my webpage but we need a way to listen in to all requests our web view is making so we can work our magic with trusting the self signed certificate (remember this part is for dev releases only and not production).

Start by creating a new class and have it inherit from NSUrlProtocol.  Then override the default delegate methods so that we can add our custom logic.

[Export ("canInitWithRequest:")]

public static bool canInitWithRequest (NSUrlRequest request)
{
   Console.WriteLine (String.Format ("URL # { 0}. Loading URL: { 1}", counter.ToString(), request.Url.ToString()));
   
   counter++;

   if (CustomNsUrlProtocol.GetProperty(MY_KEY, request) == myObj)
   {
      return false; // request has already been handled	
   }

   return true;
}

Here we get the opportunity to check all requests before they are loaded, and make a decision if we need to do something clever or not.  The default behaviour here is to return ‘true’ which means we need to do something.  So let’s do something…

public override void StartLoading ()
{
   // start loading the URL now we have handled it
   new NSUrlConnection (Request, new CustomNSUrlConnectionDataDelegate (this, new NSUrl(Constants.baseUrl)), true);
}

The clever part is to create a new instance of a NSUrlConnectionDataDelegate and use this delegate to inspect the certificate of each request.

Finally we just need to tell our custom protocol that we have now dealt with this request and we do not want to see it again.

public override NSUrlRequest Request
{
   get {
         NSMutableUrlRequest mutableRequest = (NSMutableUrlRequest)base.Request.MutableCopy ();
         CustomNsUrlProtocol.SetProperty (myObj, MY_KEY, mutableRequest);
         return mutableRequest;
   }
}

We’ve assigned an object to our request.  Now when it attempts to load, via canInitWithRequest, it will recognise that we have already dealt with this request and the browser will continue to load the request as normal.

On to the magic

So far you’ve probably noticed we haven’t actually done anything with our requests other than inspect them and assign an object to say we have done so.

Create a class that inherits from NSUrlConnectionDataDelegate and override CanAuthenticateAgainstProtectionSpace.  This method will be called if we receive an authentication for any of the requests we pass if from our NSUrlProtocol.

public override bool CanAuthenticateAgainstProtectionSpace (NSUrlConnection connection, NSUrlProtectionSpace protectionSpace)
{
   #if DEBUG || TEST
      if (protectionSpace.AuthenticationMethod.Equals (Foundation.NSUrlProtectionSpace.AuthenticationMethodServerTrust))
         return true;
      return false;
   #else
      return false;
   #endif
}

The default value we return is false which means we will not authenticate against any insecure connections.  However, if we receive a challenge and we are running in the development or test environment then we return true as this is something we want to handle.

Finally I use the delegate ReceivedAuthenticationChallenge to trust the request.

public override void ReceivedAuthenticationChallenge (NSUrlConnection connection, NSUrlAuthenticationChallenge challenge)
{
   var baseUrl = new NSUrl(Constants.baseUrl); // this is the base URL we trust

   // check we trust the host - an additional layer of security
   if (challenge.ProtectionSpace.Host.Equals (baseUrl.Host))
   {
      challenge.Sender.UseCredential (new NSUrlCredential (challenge.ProtectionSpace.ServerSecTrust), challenge);
   }
   else
   {
      Console.WriteLine ("Host not trusted: " + challenge.ProtectionSpace.Host);
   }
}

A quick check to ensure the URL is from a webpage I trust, and if so I provide my own credentials and reload the connection.  Re-run the application and if all goes well there will be a heap of URLs written to the debug log as they are ‘taken care of’ and the page will load as normal.

As always, leave a comment below if you have a question.  A sample project with the complete working code can be downloaded from here.

If you’re after more information or want to introduce more control over your request loading then I recommend this page as a starting point: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/AuthenticationChallenges.html

Azure Applications Insights for Xamarin iOS

Azure Application Insights (AI) is a great instrumentation tool that can help you learn about how your application is doing during run-time. It is currently in Preview mode, so bear that in mind when developing production ready apps. It gives you the ability to log lots of different kinds of information like tracing, page views, custom events, metrics and more.

Azure AI supports multiple platforms, but unfortunately they have not released a Xamarin package yet. There is one library which is for Xamarin.Forms since it uses the DependencyResolver. I have taken that and removed that dependency to make it compatible with Xamarin.iOS. You could do the same thing to use it for Xamarin.Android too if you like.

It’s very simple to use, all you need is your instrumentationkey which you can get from your Azure portal. Follow the steps from the MSDN tutorial as you can see here to create the Azure AI instance and get your key. Once done, you could download and reference the repository that I have created on GitHub, as you can find it here.

To start Azure AI on your Xamarin iOS app, you could do:

    
	AzureAIManager.Setup();

	AzureAIManager.Configure("my-user-or-device-name");

	AzureAIManager.Start();

The implementation of the AzureAIManager is as follows:


	public static class AzureAIManager
	{
		public static void Setup(string appKey = "your-azure-AI-instrumentation-key")
		{
			AI.Xamarin.iOS.ApplicationInsights.Init();

			var ai = new AI.Xamarin.iOS.ApplicationInsights ();
			ApplicationInsights.Init (ai);

			TelemetryManager.Init(new AI.Xamarin.iOS.TelemetryManager());
			ApplicationInsights.Setup(appKey);

		}

		public static void Start()
		{
			ApplicationInsights.Start();
		}

		public static void Configure(string userId = "" )
		{
			ApplicationInsights.SetAutoPageViewTrackingDisabled(true);

			if (string.IsNullOrEmpty(userId))
				ApplicationInsights.SetUserId(userId);
		}

		public static void RenewSession()
		{
			ApplicationInsights.StartNewSession();
		}
	}

I have not put this as a Nuget package because I am sure Microsoft will release one very soon, so until that happens, you can use this bindings to play around with Azure AI and you could even use it on your small projects.

Let’s Hack It: Securing data on the mobile, the what, why, and how

Our solution to secure the mobile app data

Our solution to secure the mobile app data. It uses open source libraries and took a very minimal effort to implement

Here is the presentation of tonight’s talk. It was great to see so many passionate developers and business people at Melbourne Mobile. I have embedded the slides below and I hope you find it useful.

Talk Summary

This presentation is basically a summary of what I have learned and the experience I have had going through my recent project. In trying to secure the users data on the mobile device, I have come to learn quite few common flaws in the security implementation, I have learned more reasons why you need to protect the data on your mobile app, and have come to know and use few useful open source projects. I share my experience from this project hoping that it would help you gain some insight and protect your mobile app data easily.

I said in the presentation that you could start securing the app data by a couple of lines of code and I do mean it. In fact, if you use SQLCipher, then you could do that by only changing one line of code :). I have put the links to all my reference and the libraries I have used at the end of the slides.

Let's Hack It Presentation

Let’s Hack It Presentation

Finally, just in case you do not like Prezi, here is the slides as a PDF file:
Let’s Hack It, the presentation as PDF

Announcing KeyChain.NET: a unified API for using KeyChain on many platforms

Storing and accessing private keys and passwords can be a tricky task. How far do you need to go to protect your (and the user’s) data? This is where KeyChain on iOS comes in handy. It allows you to store keys in a (arguably) secure database. This has seen great improvements since iOS 8 and iOS devices (since iPhone 5S) equipped with a special A7 chip designed particularly for holding your keys. More on iOS KeyChain can be found on Apple’s website here. Android, on the other side has its KeyStore, which also gives you some level of protection, but leaves a major part of the implementation to your (the developer). Details of Android KeyStore can be found on Android SDK here.

While working on recent projects, I found myself needing to have a unified way of accessing the KeyChain on both platforms. I implemented the generic library and it’s been working very well, so I thought it would be nice to share the love with the community, so here it comes 🙂

KeyChain.Net offers developers a unified, simple-to-use api for storing, accessing, and deleting keys from the keyChain (or KeyStore). It also offers further customisation capabilities based on what the platform supports. For instance, iOS KeyChain supports seamless sync (of your private keys) with other iOS devices using iCloud. This can be achieved using KeyChain.Net by turning ON the autoSyncToiCloud setting.

The package is open source and it is hosted on GitHub here. Currently, I am supporting Xamarin iOS and Xamarin Android. I might add Windows Phone depending on the feedback I get.

Keychain nuget package

Keychain nuget package

The library can be found on Nuget here. I have put some sample code on the read.me file on GitHub, and you could also look at the unit tests for information on how to use it. Tests are also available on Github.

Feel free to fork the repo on github and use it in any way you like or simply pull the nuget package to your project and enjoy it :). I would appreciate all feedback and if you have any issues or feature requests then please log them on Github.

Reachability.Net: A unified API for reachability (network connectivity) on Xamarin Android and iOS

Do you need to check for an active internet connection in your mobile app? Don’t we all do it often and on many platforms (and for almost all apps)? I found myself implementing it on iOS and Android and then pulling my implementation to almost all the mobile apps that I write. This is not efficient, and can be done better, right? 🙂

As a result I have created a library called Reachabiliy.Net which can be found as a nuget package for everything related to network connectivity. The library is open source and is hosted on Github. Currently, the solution only supports Xamarin iOS and Xamarin Android. I might add Windows Phone support and .NET 4.5 depending on the feedback I get. You will find examples listed on the main repository page.

I have included some sample code in the Github repostiroy.

The library provides a unified API across all platforms. The implementation of the library is based on the Xamarin Recipe on iOS, which can be found Xamarin’s Recipe Site. This is a good implementation and well tested.

On Android, the Xamarin Android recipe, is not really great and is based on the examples from the Android SDK docs, but it only checks whether the device is capable of connecting to the internet (or to wifi) or not and does not indicate the current connection status.

Therefore, I combined the Xamarin Android recipe with another check for connectivity to ensure correct results. More details on Reachability on Android can be found on this StackOverflow discussion.

OK, that’s all for me and I hope you enjoy using the library. Feel free to log any issues or feature requests on Github and I would love to hear your feedback.

Sharing Azure SSO Access Tokens Across Multiple Native Mobile Apps

This blog post is the fourth and final in the series that cover Azure AD SSO in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO tokens for Multiple AAD Resources From Native Mobile Apps
  4. Sharing Azure SSO Access Tokens Across Multiple Native Mobile Apps (this post).

Introduction

Most enterprises have more than one mobile app and it’s not unusual for these mobile apps to interact with some back-end services or APIs to fetch and update data. In the previous posts of this series we looked at how to manage access to APIs and share tokens as a way to enable a mobile app to interact with multiple AAD-secured resources.

This post will cover how to share access tokens to AAD resources across multiple mobile apps. This is very useful if the enterprise (or any mobile app vendor) wants to provide convenience for the users by not asking them to authenticate on every mobile app the user has.

Once a mobile user logs into Azure AD and gets a token we want to reuse the same token with other apps. This is suitable for some scenarios, but it might not be ideal for apps and resources that deal with sensitive data – the judgement is yours.

Sharing Tokens Across Multiple Mobile Apps

Moving on from previous posts it is now time to enable our mobile apps to share the access token. In this scenario we are covering iOS devices (iOS 6 and above), however other mobile platforms provide similar capabilities too. So what are the options for sharing data on iOS:

KeyChain Store

iOS offers developers a simple utility for storing and sharing keys, this is called SecKeyChain. The API has been part of the iOS platform since before iOS 6, but in iOS 6 Apple integrated this tool with iCloud, to make it even easier to push any saved passwords and keys to Apple iCloud, and then share them on multiple devices.

We could use iOS SecKeyChain to store the token (and the refreshToken) once the user logs in on any of the apps. When the user starts using any of the other apps, we check the SecKeyChain first before attempting to authenticate the user.

public async Task AsyncInit(UIViewController controller, ITokensRepository repository)
{
	_controller = controller;
	_repository = repository;
	_authContext = new AuthenticationContext(authority);
}

public async Task&lt;string&gt; RefreshTokensLocally()
{
	var refreshToken = _repository.GetKey(Constants.CacheKeys.RefreshToken, string.Empty);
	var authorizationParameters = new AuthorizationParameters(_controller);

	var result = &quot;Refreshed an existing Token&quot;;
	bool hasARefreshToken = true;

	if (string.IsNullOrEmpty(refreshToken)) 
	{
		var localAuthResult = await _authContext.AcquireTokenAsync(
			resourceId1, clientId, 
                        new Uri (redirectUrl), 
                        authorizationParameters, 
                         UserIdentifier.AnyUser, null);

		refreshToken = localAuthResult.RefreshToken;
		_repository.SaveKey(Constants.CacheKeys.WebService1Token, localAuthResult.AccessToken, null);


		hasARefreshToken = false;
		result = &quot;Acquired a new Token&quot;; 
	} 

	var refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync(refreshToken, clientId, resourceId2);
	_repository.SaveKey(Constants.CacheKeys.WebService2Token, refreshAuthResult.AccessToken, null);

	if (hasARefreshToken) 
	{
		// this will only be called when we try refreshing the tokens (not when we are acquiring new tokens. 
		refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync(refreshAuthResult.RefreshToken,  clientId,  resourceId1);
		_repository.SaveKey(Constants.CacheKeys.WebService1Token, refreshAuthResult.AccessToken, null);
	}

	_repository.SaveKey(Constants.CacheKeys.RefreshToken, refreshAuthResult.RefreshToken, null);

	return result;
}

Some of the above code will be familiar from previous posts, but what has changed is that now we are passing ITokenRepository which would save any tokens (and refreshTokens) once the user logs in to make them available for other mobile apps.

I have intentionally passed an interface (ITokenRepository) to allow for different implementations, in case you opt to use a different approach for sharing the tokens. The internal implementation of the concrete TokenRepository is something like this:

public interface ITokensRepository 
{
	bool SaveKey(string key, string val, string keyDescription);
	string GetKey(string key, string defaultValue);
	bool SaveKeys(Dictionary&lt;string,string&gt; secrets);
}

public class TokensRepository : ITokensRepository
{
	private const string _keyChainAccountName = &quot;myService&quot;;

	public bool SaveKey(string key, string val, string keyDescription)
	{
		var setResult = KeychainHelpers.SetPasswordForUsername(key, val, _keyChainAccountName, SecAccessible.WhenUnlockedThisDeviceOnly, false );

		return setResult == SecStatusCode.Success;
	}

	public string GetKey(string key, string defaultValue)
	{
		return KeychainHelpers.GetPasswordForUsername(key, _keyChainAccountName, false) ?? defaultValue;
	}
		
	public bool SaveKeys(Dictionary&lt;string,string&gt; secrets)
	{
		var result = true;
		foreach (var key in secrets.Keys) 
		{
			result = result &amp;&amp; SaveKey(key, secrets [key], string.Empty);
		}

		return result;
	}
}

iCloud

We could use Apple iCloud to push the access tokens to the cloud and share them with other apps. The approach would be similar to what we have done above with the only difference being in the way we are storing these keys. Instead of storing them locally, we push them to Apple iCloud directly. As the SecKeyChain implementation above does support pushing data to iCloud, I won’t go through the implementation details here and simply note the option is available for you.

Third Party Cloud Providers (ie Azure)

Similar to the previous option, but offer more flexibility. This is a very good solution if we already are already using Azure Mobile Services for our mobile app. We can create one more table and then use this table to store and share access tokens. The implementation of this could be similar to the following:

public async Task&lt;string&gt; RefreshTokensInAzureTable()
{
	var tokensListOnAzure = await tokensTable.ToListAsync();
	var tokenEntry = tokensListOnAzure.FirstOrDefault();
	var authorizationParameters = new AuthorizationParameters(_controller);

	var result = &quot;Refreshed an existing Token&quot;;
	bool hasARefreshToken = true;

	if (tokenEntry == null) 
	{
		var localAuthResult = await _authContext.AcquireTokenAsync(resourceId1, clientId, new Uri (redirectUrl),  authorizationParameters, UserIdentifier.AnyUser, null);

		tokenEntry = new Tokens {
			WebApi1AccessToken = localAuthResult.AccessToken,
			RefreshToken = localAuthResult.RefreshToken,
			Email = localAuthResult.UserInfo.DisplayableId,
			ExpiresOn = localAuthResult.ExpiresOn
		};
		hasARefreshToken = false;
		result = &quot;Acquired a new Token&quot;; 
	} 
		
	var refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync(tokenEntry.RefreshToken, 
                                                                                    clientId, 
                                                                                    resourceId2);
	tokenEntry.WebApi2AccessToken = refreshAuthResult.AccessToken;
	tokenEntry.RefreshToken = refreshAuthResult.RefreshToken;
	tokenEntry.ExpiresOn = refreshAuthResult.ExpiresOn;

	if (hasARefreshToken) 
	{
		// this will only be called when we try refreshing the tokens (not when we are acquiring new tokens. 
		refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync (refreshAuthResult.RefreshToken, clientId, resourceId1);
		tokenEntry.WebApi1AccessToken = refreshAuthResult.AccessToken;
		tokenEntry.RefreshToken = refreshAuthResult.RefreshToken;
		tokenEntry.ExpiresOn = refreshAuthResult.ExpiresOn;
	}

	if (hasARefreshToken)
		await tokensTable.UpdateAsync (tokenEntry);
	else
		await tokensTable.InsertAsync (tokenEntry);

	return result;
}

Words of Warning

Bearer Tokens

Developers need to understand Bearer Tokens when using Azure AD authentication. Bearer Tokens mean anybody who has the token (bearer of the token) could access and interact with your AAD resource. This offers high flexibility but it could also be a security risk if your key was exposed somehow. This needs to be thought of when implementing any token sharing mechanism.

iOS SecKeyChain is “Secure”

iOS SecKeyChain is “Secure”, right? No, not at all. Apple calls it secure, but on jail-broken devices, you could see the key store as a normal file. Thus, I would highly recommend encrypting these access tokens and any key that you might want to store before persisting it. The same goes for iCloud, Azure, or any of the other approaches we went through above.

Apple AppStore Verification

If you intend on submitting your app to Apple AppStore, then you need to be extra careful with what approach you take to share data between your apps. For enterprises (locally deployed apps), you have the control and you make the call based on your use case. However, Apple has a history of rejecting apps (ie PastePane) for using some of iOS APIs in “an unintended” manner.

I hope you found this series of posts useful, and as usual, if there is something not clear or you need some help with similar projects that you are undertaking, then get in touch, and we will do our best to help. I have pushed the sample code from this post and the previous ones to GitHub, and can be found here

Has.

This blog post is the fourth and final in the series that cover Azure AD SSO in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO tokens for Multiple AAD Resources From Native Mobile Apps
  4. Sharing Azure SSO Access Tokens Across Multiple Native Mobile Apps (this post).

Using Azure SSO Tokens for Multiple AAD Resources From Native Mobile Apps

This blog post is the third in a series that cover Azure Active Directory Single Sign-On (SSO) authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO tokens for Multiple AAD Resources From Native Mobile Apps (this post)
  4. Sharing Azure SSO access tokens across multiple native mobile apps.

Introduction

In an enterprise context it is highly likely there are multiple web services that your native mobile app needs to consume. I had exactly this scenario at one of my clients who asked if they could maintain the same SSO token in the background in the mobile app and use it for accessing multiple web services. I spent some time digging through the documentation and conducting some experiments to confirm some points and this post is to share my findings.

Cannot Share Azure AD Tokens for Multiple Resources

The first thing that comes to mind is to use the same access token for multiple Azure AD resources. Unfortunately this is not allowed. Azure AD issues a token for a certain resource (which is mapped to an Azure AD app). When we call AcquireToken, we need to provide a single resourceID. The result is the token can only be used for resource matching the supplied identifier.

There are ways where you could use the same token (as we will see later in this post), but it is not recommended as it complicates operations logging, authentication process tracing, etc. Therefore it is better to look at the other options provided by Azure and the ADAL library.

Use Refresh-Token to Acquire Tokens for Multiple Resources

The ADAL library supports acquiring multiple access tokens for multiple resources using a “refresh token”. This means once a user is authenticated, the ADAL’s authentication context is able to generate an access token to multiple resources without authenticating the user again. This is covered briefly by the MSDN documentation. A sample implementation to retrieve this token is shown below.

public async Task<string> RefreshTokens()
{
	var tokenEntry = await tokensRepository.GetTokens();
	var authorizationParameters = new AuthorizationParameters (_controller);

	var result = "Refreshed an existing Token";
	bool hasARefreshToken = true;

	if (tokenEntry == null) 
	{
		var localAuthResult = await _authContext.AcquireTokenAsync (
			resourceId1, 
                        clientId, 
                        new Uri (redirectUrl), 
                        authorizationParameters, 
                        UserIdentifier.AnyUser, 
                        null);

		tokenEntry = new Tokens {
			WebApi1AccessToken = localAuthResult.AccessToken,
			RefreshToken = localAuthResult.RefreshToken,
			Email = localAuthResult.UserInfo.DisplayableId,
			ExpiresOn = localAuthResult.ExpiresOn
		};
		hasARefreshToken = false;
		result = "Acquired a new Token"; 
	} 

	var refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync(
                                tokenEntry.RefreshToken, 
                                clientId, 
                                resourceId2);

	tokenEntry.WebApi2AccessToken = refreshAuthResult.AccessToken;
	tokenEntry.RefreshToken = refreshAuthResult.RefreshToken;
	tokenEntry.ExpiresOn = refreshAuthResult.ExpiresOn;

	if (hasARefreshToken) 
	{
		// this will only be called when we try refreshing the tokens (not when we are acquiring new tokens. 
		refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync (
                                                     refreshAuthResult.RefreshToken, 
                                                     clientId, 
                                                     resourceId1);

		tokenEntry.WebApi1AccessToken = refreshAuthResult.AccessToken;
		tokenEntry.RefreshToken = refreshAuthResult.RefreshToken;
		tokenEntry.ExpiresOn = refreshAuthResult.ExpiresOn;
	}

	await tokensRepository.InsertOrUpdateAsync (tokenEntry);

	return result;
}

As you can see from above, we check if we have an access token from previous calls, and if we do, we refresh the access tokens for both web services. Notice how the _authContext.AcquireTokenByRefreshTokenAsync() method provides an overloading parameter that takes a resourceId. This enables us to get multiple access tokens for multiple resources without having to re-authenticate the user. The rest of the code is similar to what we have seen in the previous two posts.

ADAL Library Can Produce New Tokens For Other Resources

In the previous two posts we looked at ADAL and how it uses the TokenCache. Although ADAL does not support persistent caching of tokens yet on mobile apps, it still uses the TokenCache for in-memory caching. This enables ADAL to generate new access tokens if the AuthenticationContext still exists from previous authentication calls. Remember in the previous post we said it is recommended to keep a reference to the authentication-context? Here it comes in handy as it enables us to generate new access tokens for accessing multiple Azure AD resources.

var localAuthResult = await _authContext.AcquireTokenAsync (
                                   resourceId2, 
                                   clientId, 
                                   new Uri(redirectUrl),
                                   authorizationParameters,
                                   UserIdentifier.AnyUser, 
                                   null
                                 );

Calling AcquireToken() (even with no refresh token) would give us a new access token to the requested resource. This is due to ADAL checking if we have a refresh token in-memory which ADAL then uses that to generate a new access token for the resource.

An alternative

The third alternative is the simplest (but not necessarily the best). In this option, we can use the same access token to consume multiple Azure AD resources. To do this, we need to use the same Azure AD app ID when setting the two APIs for authentication via Azure AD. This requires some understanding of how the Azure AD authentication happens on our web apps.

If you refer to Taiseer Joudeh’s tutorial you will see that in our web app, we need to tell the authentication framework what our Authority is and the Audience (Azure AD App Id). If we set up both of our web APIs to use the same Audience (Azure AD app Id) we link them both into the same Azure AD application which allows use of the same access token to use both web APIs.

// linking our web app authentication to an Azure AD application
private void ConfigureAuth(IAppBuilder app)
{
	app.UseWindowsAzureActiveDirectoryBearerAuthentication(
		new WindowsAzureActiveDirectoryBearerAuthenticationOptions
		{
			Audience = ConfigurationManager.AppSettings["Audience"],
			Tenant = ConfigurationManager.AppSettings["Tenant"]
		});
}
<appSettings>
    <add key="Tenant" value="hasaltaiargmail.onmicrosoft.com" />
    <add key="Audience" value="http://my-Azure-AD-Application-Id" />	
</appSettings>

As I said before, this is very simple and requires less code, but could cause complications in terms of security logging and maintenance. At the end of the day, it depends on your context and what you are trying to achieve.

Conclusion

We looked at how we could use Azure AD SSO with ADAL to access multiple resources from native mobile apps. As we saw, there are three main options, and the choice could be made based on the context of your app. I hope you find this useful and if you have any questions or you need help with some development that you are doing, then just get in touch.

This blog post is the third in a series that cover Azure Active Directory Single Sign On (SSO) Authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO tokens for Multiple AAD Resources From Native Mobile Apps (this post)
  4. Sharing Azure SSO access tokens across multiple native mobile apps.