{"id":3289,"date":"2015-07-22T01:02:24","date_gmt":"2015-07-22T08:02:24","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/?p=3289"},"modified":"2015-07-22T01:04:38","modified_gmt":"2015-07-22T08:04:38","slug":"using-adal-3-x-with-xamarin-forms","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2015\/07\/22\/using-adal-3-x-with-xamarin-forms\/","title":{"rendered":"Using ADAL 3.x with Xamarin.Forms"},"content":{"rendered":"<p>You might have noticed that I am not blogging much lately \u2013 that\u2019s because I am heads down trying to wrap <a href=\"http:\/\/www.amazon.com\/Authentication-Directory-Applications-Developer-Reference\/dp\/0735696942\/\">this bad guy<\/a>. However today I have to take a brief break from book writing and spend some time unblocking you guys on a super hot scenario, the use of Xamarin.Forms in ADAL.<br \/>\nI have been receiving TONS for requests for it lately, and the dirty secret is that <em>the current ADAL 3.x already supports Xamarin.Forms<\/em> \u2013 we simply did not have the time to publish a sample yet!<\/p>\n<p>In this post I am going to share with you the absolute minimum code required to illustrate the approach. An official, full fledged sample will follow _ here I just want to unblock you.<\/p>\n<h2>ADALv3 and Xamarin.Forms<\/h2>\n<p>As you know from <a href=\"https:\/\/www.cloudidentity.com\/blog\/2014\/10\/30\/adal-net-v3-preview-pcl-xamarin-support\/\">this post<\/a> about our first ADAL 3.x preview, ADAL v3 supports multiple platforms via dependency injection: when you call AcquireToken you are requested to pass a pointer to the control hosting your UX, and that is enough for ADAL to infer which platform-specific assembly to load for hosting the auth UX, choose a storage tech for token caching, and so on. If you want a primer about that, <a href=\"https:\/\/sec.ch9.ms\/sessions\/build\/2015\/2-769-LG.mp4\">check out this \/\/Build session<\/a>.<\/p>\n<p>The approach does not work as-is with Xamarin.Forms, given that you define your UX in a platform-agnostic project \u2013 hence you don\u2019t yet have a reference to your platform specific UX elements. However there are various ways to solve the issue: you just need to make that binding as soon as the app lifecycle allows. The approach we like and recommend goes as follows:<\/p>\n<ul>\n<li>In the pages from which you want to perform token acquisition operations, you expose a property of type <span style=\"font-family: Courier New;\">IPlatformParameters<\/span> and you use it in <span style=\"font-family: Courier New;\">AcquireTokenAsync<\/span> flows in lieu of the concrete implementation of it<\/li>\n<li>In the platform specific projects, you provide a <span style=\"font-family: Courier New;\"><strong>PageRenderer<\/strong><\/span> for each of such pages. In that <span style=\"font-family: Courier New;\">PageRenderer<\/span> you take care of populating the aforementioned property with a the platform specific concrete implementation of <span style=\"font-family: Courier New;\">IPlatformParameter<\/span><\/li>\n<\/ul>\n<p>Pretty simple, right? Once again, you have to thank <strong>Afshin, Kanishk<\/strong> and <strong>James Montemagno <\/strong>for this neat trick <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/wlEmoticon-smile.png\" alt=\"Smile\" \/><\/p>\n<h2>A super simple sample<\/h2>\n<p>Here there\u2019s a trivial sample demonstrating the approach. It is *really* quick &amp; dirty, please make sure you refer to it only for learning the <span style=\"font-family: Courier New;\">PageRenderer\/IPlatformParameter<\/span> pattern and discard everything else <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/wlEmoticon-smile.png\" alt=\"Smile\" \/>.<\/p>\n<p>Assuming that you have Xamarin installed on your system and your licensing level allows the use of Xamarin.Forms.<\/p>\n<ul>\n<li>Open VS and create a new project. Select Mobile Projects and pick Xamarin.Forms Portable.<\/li>\n<li>Add a NuGet reference to ADAL 3.x (from the prerelease feed) to both the Portable project and the iOS one\n<ul>\n<li>I will leave Android as an exercise to the reader, and Windows Phone 8 is not supported by ADAL hence you can discard the corresponding project.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Let\u2019s first work on the Portable project. Open App.cs and modify it so that it looks as follows (module your namespace, of course):<\/p>\n<pre class=\"csharpcode\"><span class=\"kwrd\">using<\/span> Xamarin.Forms;\r\n<span class=\"kwrd\">namespace<\/span> X.FormsADALvs2013\r\n{\r\n    <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">class<\/span> App : Application\r\n    {        \r\n        <span class=\"kwrd\">public<\/span> App()\r\n        {\r\n            MainPage = <span class=\"kwrd\">new<\/span> MyPage();\r\n        }\r\n    }\r\n}<\/pre>\n<p>That done, add a Content page to the project and name it MyPage.<\/p>\n<p>Here there\u2019s the complete source. Don\u2019t be intimidated by it, as soon as you know how to read it you\u2019ll find it trivial.<\/p>\n<div class=\"csharpcode\">\n<pre><span class=\"lnum\">   1:  <\/span><span class=\"kwrd\">using<\/span> Microsoft.IdentityModel.Clients.ActiveDirectory;<\/pre>\n<pre><span class=\"lnum\">   2:  <\/span><span class=\"kwrd\">using<\/span> System;<\/pre>\n<pre><span class=\"lnum\">   3:  <\/span><span class=\"kwrd\">using<\/span> Xamarin.Forms;<\/pre>\n<pre><span class=\"lnum\">   4:  <\/span><\/pre>\n<pre><span class=\"lnum\">   5:  <\/span><span class=\"kwrd\">namespace<\/span> X.FormsADALvs2013<\/pre>\n<pre><span class=\"lnum\">   6:  <\/span>{<\/pre>\n<pre><span class=\"lnum\">   7:  <\/span>    <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">class<\/span> MyPage : ContentPage<\/pre>\n<pre><span class=\"lnum\">   8:  <\/span>    {<\/pre>\n<pre><span class=\"lnum\">   9:  <\/span>        <span class=\"kwrd\">public<\/span> IPlatformParameters platformParameters { get; set; }<\/pre>\n<pre><span class=\"lnum\">  10:  <\/span>        <span class=\"kwrd\">private<\/span> Label results;<\/pre>\n<pre><span class=\"lnum\">  11:  <\/span><\/pre>\n<pre><span class=\"lnum\">  12:  <\/span>        async <span class=\"kwrd\">void<\/span> getTokenButton_Clicked(<span class=\"kwrd\">object<\/span> sender, EventArgs e)<\/pre>\n<pre><span class=\"lnum\">  13:  <\/span>        {<\/pre>\n<pre><span class=\"lnum\">  14:  <\/span>                AuthenticationContext ac =<\/pre>\n<pre><span class=\"lnum\">  15:  <\/span>                    <span class=\"kwrd\">new<\/span> AuthenticationContext(<span class=\"str\">\"https:\/\/login.microsoftonline.com\/common\"<\/span>);<\/pre>\n<pre><span class=\"lnum\">  16:  <\/span>                AuthenticationResult ar = await ac.AcquireTokenAsync(<\/pre>\n<pre><span class=\"lnum\">  17:  <\/span>                    <span class=\"str\">\"https:\/\/graph.windows.net\"<\/span>,<\/pre>\n<pre><span class=\"lnum\">  18:  <\/span>                    <span class=\"str\">\"e11a0451-ac9d-4c89-afd8-d2fa3322ef68\"<\/span>,<\/pre>\n<pre><span class=\"lnum\">  19:  <\/span>                    <span class=\"kwrd\">new<\/span> Uri(<span class=\"str\">\"http:\/\/li\"<\/span>),<\/pre>\n<pre><span class=\"lnum\">  20:  <\/span>                    platformParameters);<\/pre>\n<pre><span class=\"lnum\">  21:  <\/span>                results.Text = <span class=\"str\">\"got a token for \"<\/span> + ar.UserInfo.GivenName;<\/pre>\n<pre><span class=\"lnum\">  22:  <\/span>        }<\/pre>\n<pre><span class=\"lnum\">  23:  <\/span>        <span class=\"kwrd\">public<\/span> MyPage()<\/pre>\n<pre><span class=\"lnum\">  24:  <\/span>        {<\/pre>\n<pre><span class=\"lnum\">  25:  <\/span>            var getTokenButton = <span class=\"kwrd\">new<\/span> Button<\/pre>\n<pre><span class=\"lnum\">  26:  <\/span>            {<\/pre>\n<pre><span class=\"lnum\">  27:  <\/span>                Text = <span class=\"str\">\"Get token\"<\/span><\/pre>\n<pre><span class=\"lnum\">  28:  <\/span>            };<\/pre>\n<pre><span class=\"lnum\">  29:  <\/span>            getTokenButton.Clicked += getTokenButton_Clicked;<\/pre>\n<pre><span class=\"lnum\">  30:  <\/span>            results = <span class=\"kwrd\">new<\/span> Label();<\/pre>\n<pre><span class=\"lnum\">  31:  <\/span><\/pre>\n<pre><span class=\"lnum\">  32:  <\/span>            Content = <span class=\"kwrd\">new<\/span> StackLayout<\/pre>\n<pre><span class=\"lnum\">  33:  <\/span>            {<\/pre>\n<pre><span class=\"lnum\">  34:  <\/span>                Children = {<\/pre>\n<pre><span class=\"lnum\">  35:  <\/span>                    getTokenButton,results<\/pre>\n<pre><span class=\"lnum\">  36:  <\/span>                }<\/pre>\n<pre><span class=\"lnum\">  37:  <\/span>            };<\/pre>\n<pre><span class=\"lnum\">  38:  <\/span>        }<\/pre>\n<pre><span class=\"lnum\">  39:  <\/span>    }<\/pre>\n<pre><span class=\"lnum\">  40:  <\/span>}<\/pre>\n<\/div>\n<p>As described in the general pattern, the page exposes one property of type <span style=\"font-family: Courier New;\">IPlatformParameter<\/span> (line 9).<\/p>\n<p>The lines form 12 to 22 are a simple click event handler which do the good old ADAL interactive token acquisition flow to get a token for the Graph API, then optimistically (no error handling \u2013 quick &amp; dirty!) displays the first name of the user who just obtained the token.<\/p>\n<p>The rest of the file takes care of assembling the page layout. And that\u2019s it!<\/p>\n<p>Let\u2019s now focus on the iOS project.<\/p>\n<p>All you need to do here is to add a new class and name it MyPageRenderer. Here there\u2019s the full source:<\/p>\n<pre><span class=\"lnum\">   1:  <\/span><span class=\"kwrd\">using<\/span> Microsoft.IdentityModel.Clients.ActiveDirectory;<\/pre>\n<pre><span class=\"lnum\">   2:  <\/span><span class=\"kwrd\">using<\/span> X.FormsADALvs2013;<\/pre>\n<pre><span class=\"lnum\">   3:  <\/span><span class=\"kwrd\">using<\/span> X.FormsADALvs2013.iOS;<\/pre>\n<pre><span class=\"lnum\">   4:  <\/span><span class=\"kwrd\">using<\/span> Xamarin.Forms;<\/pre>\n<pre><span class=\"lnum\">   5:  <\/span><span class=\"kwrd\">using<\/span> Xamarin.Forms.Platform.iOS;<\/pre>\n<pre><span class=\"lnum\">   6:  <\/span><\/pre>\n<pre><span class=\"lnum\">   7:  <\/span>[assembly: ExportRenderer(<span class=\"kwrd\">typeof<\/span>(MyPage), <span class=\"kwrd\">typeof<\/span>(MyPageRenderer))]<\/pre>\n<pre><span class=\"lnum\">   8:  <\/span><span class=\"kwrd\">namespace<\/span> X.FormsADALvs2013.iOS<\/pre>\n<pre><span class=\"lnum\">   9:  <\/span>{<\/pre>\n<pre><span class=\"lnum\">  10:  <\/span>    <span class=\"kwrd\">class<\/span> MyPageRenderer: PageRenderer<\/pre>\n<pre><span class=\"lnum\">  11:  <\/span>    {<\/pre>\n<pre><span class=\"lnum\">  12:  <\/span>        MyPage page;<\/pre>\n<pre><span class=\"lnum\">  13:  <\/span><\/pre>\n<pre><span class=\"lnum\">  14:  <\/span>         <span class=\"kwrd\">protected<\/span> <span class=\"kwrd\">override<\/span> <span class=\"kwrd\">void<\/span> OnElementChanged (VisualElementChangedEventArgs e)<\/pre>\n<pre><span class=\"lnum\">  15:  <\/span>         {<\/pre>\n<pre><span class=\"lnum\">  16:  <\/span>             <span class=\"kwrd\">base<\/span>.OnElementChanged (e);<\/pre>\n<pre><span class=\"lnum\">  17:  <\/span>             page = e.NewElement <span class=\"kwrd\">as<\/span> MyPage;<\/pre>\n<pre><span class=\"lnum\">  18:  <\/span>         }<\/pre>\n<pre><span class=\"lnum\">  19:  <\/span><\/pre>\n<pre><span class=\"lnum\">  20:  <\/span>        <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">override<\/span> <span class=\"kwrd\">void<\/span> ViewDidLoad ()<\/pre>\n<pre><span class=\"lnum\">  21:  <\/span>         {<\/pre>\n<pre><span class=\"lnum\">  22:  <\/span>             <span class=\"kwrd\">base<\/span>.ViewDidLoad ();<\/pre>\n<pre><span class=\"lnum\">  23:  <\/span>             page.platformParameters = <span class=\"kwrd\">new<\/span> PlatformParameters(<span class=\"kwrd\">this<\/span>);<\/pre>\n<pre><span class=\"lnum\">  24:  <\/span>         }<\/pre>\n<pre><span class=\"lnum\">  25:  <\/span><\/pre>\n<pre><span class=\"lnum\">  26:  <\/span>    }<\/pre>\n<pre><span class=\"lnum\">  27:  <\/span>}<\/pre>\n<p>Super important: line 7. That\u2019s the line that tells the runtime how to match this renderer to its page.<\/p>\n<p>The code in itself is straightforward. The renderer keeps a reference to the page it is being applied to, via the property page (line 12) which is assigned via the <span style=\"font-family: Courier New;\">OnElementChanged<\/span> event (14 to 18).<\/p>\n<p><span style=\"font-family: Courier New;\">ViewDidLoad<\/span> creates for us the opportunity to assign to the page the iOS specific concrete implementation of <span style=\"font-family: Courier New;\">IPlatformParameters<\/span>, <span style=\"font-family: Courier New;\">PlatformParameters<\/span>.<\/p>\n<p>Believe it or not, that\u2019s it! Let\u2019s give it a spin. Make sure that you have a Mac with the Xamarin.iOS Build Host running and paired to your VS instance, that the iOS project is the startup project in the solution, and that you selected your favorite emulator flavor &#8211; then hit F5. On your companion Mac you will see the following:<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.49.38.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Screenshot 2015-07-22 00.49.38\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.49.38_thumb.png\" alt=\"Screenshot 2015-07-22 00.49.38\" width=\"292\" height=\"480\" border=\"0\" \/><\/a><\/p>\n<p>Hit Get Token.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.50.34.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Screenshot 2015-07-22 00.50.34\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.50.34_thumb.png\" alt=\"Screenshot 2015-07-22 00.50.34\" width=\"292\" height=\"480\" border=\"0\" \/><\/a><\/p>\n<p>You should get prompted. Enter the credentials of any Azure AD user you want to use for this test.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.50.57.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Screenshot 2015-07-22 00.50.57\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.50.57_thumb.png\" alt=\"Screenshot 2015-07-22 00.50.57\" width=\"292\" height=\"480\" border=\"0\" \/><\/a><\/p>\n<p>You will get prompted for consent. Grant it, and\u2026<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.51.10.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Screenshot 2015-07-22 00.51.10\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/Screenshot-2015-07-22-00.51.10_thumb.png\" alt=\"Screenshot 2015-07-22 00.51.10\" width=\"292\" height=\"480\" border=\"0\" \/><\/a><\/p>\n<p>\u2026voila\u2019! Les tr\u00e8s jolis token.<\/p>\n<p>To do the same on Android, you just create the appropriate PageRenderer in the Android project. You can read more about PageRenderes <a href=\"https:\/\/blog.xamarin.com\/?s=pagerenderer\">here<\/a>.<\/p>\n<h2>Summary<\/h2>\n<p>Using Xamarin.Forms with ADAL v3 is super easy! Apologies for not having posted a full sample yet: we are busy cooking veeeery interesting stuff, which we\u2019ll unveil soon \u2013 and as soon as we\u2019re past that, we\u2019ll refresh the samples as appropriate. In the meanwhile, I hope the above will unblock you <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2015\/07\/wlEmoticon-smile.png\" alt=\"Smile\" \/> happy cross platform coding!!!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You might have noticed that I am not blogging much lately \u2013 that\u2019s because I am heads down trying to wrap this bad guy. However today I have to take a brief break from book writing and spend some time unblocking you guys on a super hot scenario, the use of Xamarin.Forms in&#8230;<\/p>\n","protected":false},"author":1,"featured_media":3283,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3289","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/3289","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=3289"}],"version-history":[{"count":2,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/3289\/revisions"}],"predecessor-version":[{"id":3292,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/3289\/revisions\/3292"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/3283"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=3289"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=3289"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=3289"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}