{"id":46848,"date":"2020-03-30T10:01:47","date_gmt":"2020-03-30T17:01:47","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/xamarin\/?p=46848"},"modified":"2020-04-08T09:41:15","modified_gmt":"2020-04-08T16:41:15","slug":"authentication-xamarin-essentials-aspnet","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/authentication-xamarin-essentials-aspnet\/","title":{"rendered":"Social Authentication with Xamarin.Essentials and ASP.NET Core"},"content":{"rendered":"<p>Many apps require adding user authentication. This often means enabling users to sign into existing Microsoft, Facebook, Google, and (now) Apple Sign-In accounts.<\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/active-directory\/develop\/msal-overview\" rel=\"noopener noreferrer\" target=\"_blank\">Microsoft Authentication Library (MSAL)<\/a> provides an excellent turn-key solution to adding authentication to your app. Additionally, there is even support for Xamarin apps in their client NuGet package.<\/p>\n<p>However, if you are looking for a way to easily integrate Xamarin social authentication into a new or existing ASP.NET (or other) web app, Xamarin.Essentials has you covered!<\/p>\n<h2>Authentication at the Backend<\/h2>\n<p>Many authentication providers only offer explicit or &#8220;two-legged&#8221; authentication flows to ensure better security. This means you will need a &#8216;secret&#8217; from the provider to complete the authentication flow. Unfortunately, mobile apps are not a great place to store secrets. Anything stored in a mobile app&#8217;s code or otherwise is generally considered insecure. The best practice here, is to use a web backend as a middle layer between your mobile app and the authentication provider.<\/p>\n<blockquote><p>We strongly recommend against using older mobile-only authentication libraries and patterns which do not leverage a web backend in the authentication flow.<\/p><\/blockquote>\n<p>There are a lot of moving parts to this type of flow, but that doesn&#8217;t mean it needs to be difficult!<\/p>\n<h2>Web Authenticator API<\/h2>\n<p>In <a href=\"https:\/\/docs.microsoft.com\/xamarin\/essentials\/release-notes\/1.5\" rel=\"noopener noreferrer\" target=\"_blank\">Xamarin.Essentials 1.5.1<\/a> we are introducing the <code>WebAuthenticator<\/code> API. This is designed to do the heavy lifting of opening a URL in the browser. Then waiting for that browser session to redirect to your app&#8217;s callback URI. In other words: dealing with a typical external authentication flow.\nThe API is simple. It is a single method <code>AuthenticateAsync<\/code> which takes two parameters. The url that starts the authentication flow, and the Uri that your app is registered to handle the callback on. The result is a <code>WebAuthenticatorResult<\/code> which includes any query parameters parsed from the callback URI.<\/p>\n<pre><code>var authResult = WebAuthenticator.AuthenticateAsync(\r\n            new Uri(\"https:\/\/mysite.com\/mobileauth\/Microsoft\"),\r\n            new Uri(\"myapp:\/\/\"));\r\n    \r\nvar accessToken = authResult?.AccessToken;\r\n<\/code><\/pre>\n<p>The Web Authenticator will take care of opening a Safari view controller on iOS or a Custom Tab on Android. This will display the authentication URL to your user. When the user completes the flow, and your server calls back to the callback URI, the result is returned. If the user cancels the flow at any time, a null result is returned.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/03\/aoPHMyhA-1.png\" alt=\"Social Authentication Web authenticator flow\" width=\"884\" height=\"376\" class=\"aligncenter size-full wp-image-46850\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/03\/aoPHMyhA-1.png 884w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/03\/aoPHMyhA-1-300x128.png 300w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/03\/aoPHMyhA-1-768x327.png 768w\" sizes=\"(max-width: 884px) 100vw, 884px\" \/><\/p>\n<p>On iOS we take advantage of <code>ASWebAuthenticationSession<\/code> to handle this. Yet gracefully fall back to using <code>SFAuthenticationSession<\/code> or <code>SFSafariViewController<\/code> depending on the iOS version at runtime. On Android, this uses Custom Tabs to launch a browser intent. On UWP, we are using <code>WebAuthenticationBroker<\/code>. For each platform, we strive to deliver the best native experience possible.<\/p>\n<h2>Mobile Platform Setup<\/h2>\n<p>Each platform handles navigating in web browsers for authentication flows a little differently. As well as requires some specific setting up.<\/p>\n<h3>iOS<\/h3>\n<p>On iOS you will need to add your app&#8217;s callback URI pattern to your <a href=\"https:\/\/docs.microsoft.com\/xamarin\/ios\/app-fundamentals\/property-lists#custom-urls\" rel=\"noopener noreferrer\" target=\"_blank\">Info.plist<\/a>.  As a best practice, consider using <a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/inter-process_communication\/allowing_apps_and_websites_to_link_to_your_content\" rel=\"noopener noreferrer\" target=\"_blank\">Universal App Links<\/a> to register your app&#8217;s callback URI.\nAdditionally, you will also need to override your <code>AppDelegate<\/code>&#8216;s <code>OpenUrl<\/code> method to call into Essentials:<\/p>\n<pre><code>\r\n    public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)\r\n    {\r\n        if (Xamarin.Essentials.Platform.OpenUrl(app, url, options))\r\n            return true;\r\n    \r\n        return base.OpenUrl(app, url, options);\r\n    }\r\n<\/code><\/pre>\n<h3>Android<\/h3>\n<p>Android requires an Intent Filter setup to handle your callback URI. This is easily accomplished by subclassing the <code>WebAuthenticatorCallbackActivity<\/code> class:<\/p>\n<pre><code>\r\n    const string CALLBACK_SCHEME = \"myapp\";\r\n    \r\n    [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop)]\r\n    [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, DataScheme = CALLBACK_SCHEME)]\r\n    public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity\r\n    {\r\n    }\r\n<\/code><\/pre>\n<p>In your <code>MainActivity<\/code>, add a call to Essentials in your <code>OnResume<\/code>:<\/p>\n<pre><code>\r\n    protected override void OnResume()\r\n    {\r\n        base.OnResume();\r\n    \r\n        Xamarin.Essentials.Platform.OnResume();\r\n    }\r\n<\/code><\/pre>\n<h3>UWP<\/h3>\n<p>For UWP, declare your callback URI in your <code>Package.appxmanifest<\/code> file:<\/p>\n<pre><code>    &lt;Extensions&gt;\r\n        &lt;uap:Extension Category=&quot;windows.protocol&quot;&gt;\r\n            &lt;uap:Protocol Name=&quot;myapp&quot;&gt;\r\n                &lt;uap:DisplayName&gt;My App&lt;\/uap:DisplayName&gt;\r\n            &lt;\/uap:Protocol&gt;\r\n        &lt;\/uap:Extension&gt;\r\n    &lt;\/Extensions&gt;\r\n<\/code><\/pre>\n<h2>Apple Sign In<\/h2>\n<p>For using social authentication in your app, chances are you are also adding Apple Sign In. We have you covered on iOS, Android, and UWP.<\/p>\n<p>First, <a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/ios\/platform\/ios13\/sign-in\" rel=\"noopener noreferrer\" target=\"_blank\">configure your app<\/a> to use Apple Sign In.<\/p>\n<p>For iOS 13 and higher, use the <code>AppleSignInAuthenticator.AuthenticateAsync()<\/code> method. This will call the native Apple Sign in API&#8217;s under the hood so users get the best experience possible on these devices. Write your shared code to use the right API at runtime like this:<\/p>\n<pre><code>\r\n    var scheme = \"...\"; \/\/ Apple, Microsoft, Google, Facebook, etc.\r\n    WebAuthenticatorResult r = null;\r\n    \r\n    if (scheme.Equals(\"Apple\")\r\n        && DeviceInfo.Platform == DevicePlatform.iOS\r\n        && DeviceInfo.Version.Major >= 13)\r\n    {\r\n        \/\/ Use Native Apple Sign In API's\r\n        r = await AppleSignInAuthenticator.AuthenticateAsync();\r\n    }\r\n    else\r\n    {\r\n        \/\/ Web Authentication flow\r\n        var authUrl = new Uri(authenticationUrl + scheme);\r\n        var callbackUrl = new Uri(\"xamarinessentials:\/\/\");\r\n    \r\n        r = await WebAuthenticator.AuthenticateAsync(authUrl, callbackUrl);\r\n    }\r\n    \r\n    var accessToken = r?.AccessToken;\r\n<\/code><\/pre>\n<p>For non-iOS 13 devices, this will start the web authentication flow. This can also be used to enable Apple Sign In on Android and UWP devices.<\/p>\n<h3>Web Authentication with ASP.NET<\/h3>\n<p>It is possible to use the <code>WebAuthenticator<\/code> API with any web backend. However, using ASP.NET Core makes this process super easy.<\/p>\n<p>Set up all desired providers just like you would setup any <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/security\/authentication\/social\" rel=\"noopener noreferrer\" target=\"_blank\">external social authentication provider<\/a>.<\/p>\n<p>There are two additional things needed for this example to work:<\/p>\n<ol>\n<li>Use <code>.AddCookies()<\/code> in your Startup.cs <code>.AddAuthentication()<\/code> call<\/li>\n<li>All providers must be configured with <code>.SaveTokens = true;<\/code><\/li>\n<\/ol>\n<p>To include Apple Sign In, use the <code>AspNet.Security.OAuth.Apple<\/code> NuGet package. View the full <a href=\"https:\/\/github.com\/xamarin\/Essentials\/blob\/develop\/Samples\/Sample.Server.WebAuthenticator\/Startup.cs#L33-L65\" rel=\"noopener noreferrer\" target=\"_blank\">Startup.cs sample<\/a> in the Essentials GitHub repository.<\/p>\n<h2>Adding a Custom Mobile Auth Controller<\/h2>\n<p>With a mobile authentication flow, we typically want to initiate the flow directly to a provider that the user has chosen. (Such as: clicking a &#8220;Microsoft&#8221; button on the sign-in screen of an app.) We also want to be able to return relevant information to our app at a specific callback URI to end the authentication flow.<\/p>\n<p>To achieve this we can use a custom API Controller:<\/p>\n<pre><code>\r\n    [Route(\"mobileauth\")]\r\n    [ApiController]\r\n    public class AuthController : ControllerBase\r\n    {\r\n        const string callbackScheme = \"myapp\";\r\n    \r\n        [HttpGet(\"{scheme}\")] \/\/ eg: Microsoft, Facebook, Apple, etc\r\n        public async Task Get([FromRoute]string scheme)\r\n        {\r\n            \/\/ 1. Initiate authentication flow with the scheme (provider)\r\n            \/\/ 2. When the provider calls back to this URL\r\n            \/\/    a. Parse out the result\r\n            \/\/    b. Build the app callback URL\r\n            \/\/    c. Redirect back to the app\r\n        }\r\n    }\r\n<\/code><\/pre>\n<p>The purpose of this controller is to infer the scheme (provider) that the app is requesting. As well as initiate the authentication flow with the social provider. When the provider calls back to the web backend, the controller parses out the result and redirects to the app&#8217;s callback URI with parameters.<\/p>\n<p>Sometimes, you may want to return things like the provider&#8217;s <code>access_token<\/code> back to the app. This can be done via the callback URI&#8217;s query parameters. Alternatively, you may want to create your own identity on your server and pass back your own token to the app. What and how you do this part is up to you!<\/p>\n<p>Check out the <a href=\"https:\/\/github.com\/xamarin\/Essentials\/blob\/develop\/Samples\/Sample.Server.WebAuthenticator\/Controllers\/MobileAuthController.cs\" rel=\"noopener noreferrer\" target=\"_blank\">full controller sample<\/a> in the Essentials repository.<\/p>\n<h2>Get Started with Authentication<\/h2>\n<p>Xamarin.Essentials&#8217; Web Authenticator API gives you the ability to easily add an authentication flow into your app using any web backend. ASP.NET core makes it extremely simple to plug in popular social authentication providers to connect your app with.<\/p>\n<p>Check out the <a href=\"https:\/\/github.com\/xamarin\/Essentials\/blob\/develop\/Samples\/Samples\/ViewModel\/WebAuthenticatorViewModel.cs\" rel=\"noopener noreferrer\" target=\"_blank\">Xamarin.Forms<\/a> and <a href=\"https:\/\/github.com\/xamarin\/Essentials\/tree\/develop\/Samples\/Sample.Server.WebAuthenticator\" rel=\"noopener noreferrer\" target=\"_blank\">ASP.NET Core<\/a> samples for more information. As well as our awesome, new <a href=\"https:\/\/docs.microsoft.com\/xamarin\/essentials\/web-authenticator\" rel=\"noopener noreferrer\" target=\"_blank\">WebAuthenticator documentation<\/a> to get started today!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Many apps require adding user authentication, and this often means enabling your users to sign in their existing Microsoft, Facebook, Google, and now Apple Sign In accounts. With Xamarin.Essentials&#8217; new WebAuthenticator and using ASP.NET Core on your backend it has never been easier. Learn more!<\/p>\n","protected":false},"author":560,"featured_media":46850,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[313,303,1,291,367],"tags":[7887,1278,8355,8356,24],"class_list":["post-46848","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-ios","category-xamarin","category-xamarin-platform","category-xamarin-forms","tag-asp-net","tag-authentication","tag-essentials","tag-oauth","tag-xamarin-essentials"],"acf":[],"blog_post_summary":"<p>Many apps require adding user authentication, and this often means enabling your users to sign in their existing Microsoft, Facebook, Google, and now Apple Sign In accounts. With Xamarin.Essentials&#8217; new WebAuthenticator and using ASP.NET Core on your backend it has never been easier. Learn more!<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/46848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/560"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=46848"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/46848\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/46850"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=46848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=46848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=46848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}