Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Details

Miljenko Cvjetko moljac edited this page May 12, 2017 · 6 revisions

Details

Components-XamarinAuth

Xamarin.Auth helps developers authenticate users via standard authentication mechanisms (e.g. OAuth 1.0 and 2.0), and store user credentials. It's also straightforward to add support for non-standard authentication schemes.

Current version and status

  • nuget version 1.5.0
    • Native UI (CustomTabs on Android and SFSafariViewController on iOS)
    • Xamarin.Forms support
      • Xamarin.Android (tested)
      • Xamarin.iOS (tested)
      • Windows platforms (tests in progress)
    • Xamarin.iOS Embedded Browser WKWebView support as alternative WKWebView instead of UIWebView

Change Log

Status

CI servers:

Xamarin.Auth has grown into fully fledged cross platform library supporting:

  • Xamarin.Android
  • Xamarin.iOS (Unified only, Classic Support is removed)
  • Windows Phone Silverlight 8 (8.1 redundant)
  • Windows Store 8.1 WinRT
  • Windows Phone 8.1 WinRT
  • Universal Windows Platform (UWP)

The library is cross-platform, so once user learns how to use it on one platform, it is fairly simple to use it on other platforms.

Recent changes in Xamarin.Auth brought in new functionalities which caused minor breaking changes. Version 1.4.x broke GetUI() API, because it returned System.Object instead of Intent on Android and UIViewController on iOS. Efforts to add Xamarin.Forms support led to more refactoring and pushing functionality deeper into Xamarin.Auth, so version 1.5.0 reverted GetUI() API to original flavor returning UI object for each platform.

So, in version 1.5.0 GetUI() returns

  • on Android:

    • Android.Content.Intent for embedded WebViews and NativeUI
  • on iOS:

    • UIKit.UIViewController for embedded WebViews and

    • SafariServices.SFSafariViewController for Native UI

[TODO API design and breaking changes]

Work in progress and plans

  • Xamarin.Forms Windows support
  • more samples
    • Azure AD B2C
    • Azure ADAL
    • Flickr
  • restructuring samples
  • UserAgent API
    [DEPRECATED] [NOT RECOMMENDED] ToS violations workaround for attempts to fake UserAgent for Embedded Browsers to fool Google

Support

If there is need for real-time support use Xamarin Chat (community slack team) and go to #xamarin-auth-social channel where help from experienced users can be obtained. For all users without account for community slack team, please, go to self-invite link first.

Documentation - Github Wiki pages

Github

Issues

Samples (with nuget references) from the repo separated for faster development:

https://github.com/moljac/Xamarin.Auth.Samples.NugetReferences/

Xamarin Forums

https://forums.xamarin.com/search?search=auth

https://forums.xamarin.com/search?search=xamarin.auth

Stackoverflow

http://stackoverflow.com/search?q=xamarin.auth

Xamarin Chat - Community Slack Team (xamarin-auth-social room)

For those that need real-time help (hand-in-hand leading through implementation) the best option is to use community slack channel. There are numerous people that have implemented Xamarin.Auth with Native UI and maintainers/developers of the library.

https://xamarinchat.slack.com/messages/C4TD1NHPT/

For those without Xamarin Chat account please visit this page and generate self-invitation:

https://xamarinchat.herokuapp.com/

OAuth

OAuth flow (process) is setup in 4 major steps:

  1. Server side setup for OAuth service provider

    To name some:

    1. Google

      Google introduced mandatory use of Native UI for security reasons because Android CustomTabs and iOS SFSafariViewController are based on Chrome and Safari code-bases thus thoroughly tested and regulary updated. Moreover Native UI (System Browsers) have reduced API, so malicious users have less possibilities to retrieve and use sensitive data.

      Google

    2. Facebook

      Facebook

    3. Microsoft

      Microsoft

    4. Fitbit

      Fitbit is good for testing, because it allows arbitrary values for redirect_url.

      Fitbit

  2. Client side initialization of Authenticator object

    This step prepares all relevant OAuth Data in Authenticator object (client_id, redirect_url, client_secret, OAuth provider's endpoints etc)

  3. Creating and optionally customising UI

  4. Presenting/Launching UI and authenticating user

    1. Detecting/Fetching/Intercepting URL change - redirect_url and

      This substep, often called "App Linking" or "Deep Linking", is needed for NativeUI and requires a custom scheme registration for the redirect_url
      intercepting mechanism.

    2. Parsing OAuth data from redirect_url

      In order to obtain OAuth data returned redirect_url must be parsed and the best way is to let Xamarin.Auth do it automatically by parsing redirect_url

    3. Triggering Events based on OAuth data

      Parsing subsytem of the Authenticator will parse OAuth data and raise appropriate events based on returned data

  5. Using identity

    1. Using protected resources (making calls)

    2. Saving account info

    3. Retrieving account info

Xamarin.Auth with Embedded Browser API does a lot under the hood for users, but with the Native UI step 3.1 Deep Linking (App linking) must be manually implemented by the user.

Xamarin.Auth usage

Xamarin.Auth covers 2 Xamarin technologies - traditional/standard (Xamarin.Android, Xamarin.iOS) and Xamarin.Forms. The library implements nuget "bait and switch" technology.

Usage Xamarin Traditional (Standard)

Design of the library is aimed to reduce platform differences, but this is not possible in all cases (most methods in Android API need Context as a parameter), so user must be familiar with platform concepts and details.

1. Initialization

1.1 Creating and configuring an Authenticator

The server side setup of the OAuth provider defines OAuth flow used which again defines which Authenticator constructor will be used.

This code is shared accross all platforms:

OAuth2Authenticator auth = new OAuth2Authenticator
                (
                    clientId: "",
                    scope: oauth2.OAuth2_Scope,
                    authorizeUrl: oauth2.OAuth_UriAuthorization,
                    redirectUrl: oauth2.OAuth_UriCallbackAKARedirect,
                    // Native UI API switch
                    //      true    - NEW Native UI support 
                    //      false   - OLD Embedded Browser API [DEFAULT]
                    // DEFAULT will be switched to true in the near future 2017-04
                    isUsingNativeUI: test_native_ui
                )
            {
                AllowCancel = oauth1.AllowCancel,
            };                        

[TODO Link to code]

1.1 Subscribing to Authenticator events

In order to receive OAuth events Authenticator object must subscribe to the events.

Auth1.Completed += Auth_Completed;
Auth1.Error += Auth_Error;
Auth1.BrowsingCompleted += Auth_BrowsingCompleted;

[TODO Link to code]

In those events user can close the Login UI or perform further actions, based on event raised (Completed or Error) and information which can be extracted from EventArgs.

The Authenticator object has three events:

  • Completed - which is fired when an Authentication is successful,
  • Error - which is fired if the Authentication fails, and
  • BrowsingCompleted which is fired when when the browser window is closed

User will need to subscribe to these event in order to work with the data received from the authentication response.

2. Creating/Preparing UI

2.1 Creating Login UI

Creating UI step will call GetUI() method on Authenticator object which will return platform specific object to present UI for login.

This code cannot be shared for most of the platforms, because it returns platform specific objects.

On Android:

// Step 2.1 Creating Login UI 
Android.Content.Intent ui_object = Auth1.GetUI(this);

[TODO Link to code]

On iOS:

// Step 2.1 Creating Login UI 
UIKit.UIViewController ui_object = Auth1.GetUI();

[TODO Link to code]

for new API (both Embedded Browsers and Native UI Support) user will need to cast object to appropriate type:

NOTE: there is still discussion about API and returning object, so this might be subject to change.

NOTE: Windows platforms currently do NOT support Native UI embedded browser support only. Work in progress.

On Windows - Universal Windows Platform

// Step 2.1 Creating Login UI 
Type page_type = auth.GetUI();

this.Frame.Navigate(page_type, auth);

[TODO Link to code]

On Windows - WinRT - Windows Store 8.1 and Windows Phone 8.1

// Step 2.1 Creating Login UI 
System.Type page_type = auth.GetUI();

[TODO Link to code]

On Windows Phone Silverlight 8.x

// Step 2.1 Creating Login UI 
System.Uri uri = auth.GetUI ();

[TODO Link to code]

2.2 Customizing the UI - Native UI [OPTIONAL]

Embedded Browser API has limited API for UI customizations, while Native UI API is essentially more complex especially on Android.

Xamarin.Android

Native UI on Android exposes several objects to the end user which enable UI customisations like adding menus, toolbars and performance optimisations like WarmUp (preloading of the browser in the memory) and prefetching (preloading of the web site before rendering).

Those exposed objects from simpler to more complex:

  • CustomTabsIntent object which is enough for simple (basic) launch of Custom Tabs (System Browser)
  • CustomTabsIntent.Builder class which is intended for adding menus, toolbars, backbuttons and more. This object is returned by GetUI() on Android

[TODO Link to code]

[TODO finish API and more info]

Xamarin.iOS

Native UI on iOS exposes SFSafariViewController and customizations are performed through the API of that object.

[TODO Link to code]

3 Present/Launch the Login UI

This step will open a page of OAuth provider enabling user to enter the credentials and authenticate.

NOTE: there is still discussion about API and returning object, so this might be subject to change.

Xamarin.Android

// Step 3 Present/Launch the Login UI
StartActivity(ui_object);

Xamarin.iOS

// Step 3 Present/Launch the Login UI
PresentViewController(ui_object, true, null);

Windows - Universal Windows Platform

this.Frame.Navigate(page_type, auth);

[TODO Link to code]

Windows - WinRT - Windows Store 8.1 Windows Phone 8.1

this.Frame.Navigate(page_type, auth);

[TODO Link to code]

Windows Phone Silverlight 8.x

this.NavigationService.Navigate(uri);

[TODO Link to code]

3.2 Native UI support - Parsing URL fragment data

The main reason for introducing Native UI support for Installed Apps (mobile apps) is security. Both Android's [Chrome] Custom Tabs and iOS SFSafariViewController originate from (share the same codebase) the Google's Chrome browser and Apple's Safari web browser. This codebase is constantly updated and fixed. Furthemore both Custom Tabs and Safari View Controller have minimal API, so attacking surface for potential attacker is smaller. Additionally, Custom Tabs have additional features aimed at increasing performance - faster loading and prefetching.

Due to the fact that, it is impossible to obtain loaded URL from Custom Tab or Safari View Controller after redirecting to redirect url (callback) in order to parse OAuth data like auth token, user must use App Linking and custom url schemes to intercept callback.

This has some repercusions that http and https schemes will not work anymore, because Android and iOS will open default apps for those schemes and those are built in browsers (Android Browser and Safari).

NOTE: 
Android docs are showing IntentFilters with http and https schema, but after
several attempts to implement this was temporarily abandonded.
iOS will most likely open those URLs in browser, except those that were
registered with some apps based on host (Maps http://maps.google.com, 
YouTube http://www.youtube.com/ etc).

Some other schemes like mailto will open on 
    Android Intent picker to let user choose which Intent/App will handle 
    scheme
    iOS 

To enable Native UI support 3 steps are neccessary:

  1. add references to external utilities that implement NativeUI usually nuget packages.

    This step is neccessary for Android only, because CustomTabs implementation is in Xamarin.Android.Support.CustomTabs nuget. SafariServices are part of newer iOS operating systems.

  2. register custom scheme at OS level

    Operating system needs to know which application will open particular custom url scheme. This concept is called App or Deep Linking. On Android this registration is done via url handling Activity's IntentFilter and on iOS via

  3. implement platform specific code that intercepts redirect_url with custom scheme

    On Android Activity handles opening Url with custom scheme and this Activity was registered at OS level thorugh IntentFilter in step 2. On iOS user is supposed to implement OpenUrl in the AppDelegate class. When browser tries to open Url with custom scheme and the browser itself is not registered to open that scheme it will raise event on OS level and OS will check application registrations for that specific scheme. If the application is found url will be passed to Activity's OnCreate() and/or AppDelegate's OpenUrl().

Preparing app for the Native UI support

For Android app add Xamarin.Android.Support.CustomTabs package through nuget package manager.

For iOS apps - NOOP - nothing needs to be done.

Adding URL custom schema intercepting utility for parsing

Next step is to define custome scheme[s] the app can handle.

NOTE:
In the samples 
    xamarinauth
    xamarin-auth
    xamarin.auth
shemes are used.
Do NOT use those schemes, because schemes might be opened by Xamarin.Auth
sample app if they were installed (tested before).

Xamarin.Android

Add Activity with IntentFilter to catch/intercept URLs with user's custom schema:

    [Activity(Label = "ActivityCustomUrlSchemeInterceptor", NoHistory = true, LaunchMode = LaunchMode.SingleTop)]
    [
        IntentFilter
        (
            actions: new[] { Intent.ActionView },
            Categories = new[]
                    {
                        Intent.CategoryDefault,
                        Intent.CategoryBrowsable
                    },
            DataSchemes = new[]
                    {
                        "com.xamarin.traditional.standard.samples.oauth.providers.android",
                        /*
                        "com.googleusercontent.apps.1093596514437-d3rpjj7clslhdg3uv365qpodsl5tq4fn",
                        "urn:ietf:wg:oauth:2.0:oob",
                        "urn:ietf:wg:oauth:2.0:oob.auto",
                        "http://localhost:PORT",
                        "https://localhost:PORT",
                        "http://127.0.0.1:PORT",
                        "https://127.0.0.1:PORT",              
                        "http://[::1]:PORT", 
                        "https://[::1]:PORT", 
                        */
                    },
            //DataHost = "localhost",
            DataPath = "/oauth2redirect"
        )
    ]
    public class ActivityCustomUrlSchemeInterceptor : Activity
    {
        string message;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Convert iOS NSUrl to C#/netxf/BCL System.Uri - common API
            Uri uri_netfx = new Uri(uri_android.ToString());

			// load redirect_url Page (send it back to Xamarin.Auth)
			//	for Url parsing and raising Complete or Error events
            AuthenticationState.Authenticator.OnPageLoading(uri_netfx);

            this.Finish();

            return;
        }
    }
}

[TODO Link to code]

IntentFilter attribute will modify AndroidManifest.xml adding following node (user could have added this node manually to application node):

    <activity android:label="ActivityCustomUrlSchemeInterceptor" android:name="md5f8c707217af032b51f5ca5f983d46c8c.ActivityCustomUrlSchemeInterceptor">
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:host="localhost" />
        <data android:scheme="xamarinauth" />
        <data android:scheme="xamarin-auth" />
        <data android:scheme="xamarin.auth" />
      </intent-filter>
    </activity>

[TODO Link to code]

Xamarin.iOS

Register custom schemes to Info.plist by opening editor in Advanced tab and add schemes in URL types with Role Viewer.

This will result in following Info.plist snippet:

<!--
	Info.plist
-->
<key>CFBundleURLTypes</key>
<array>
	<dict>
		<key>CFBundleURLName</key>
		<string>Xamarin.Auth Google OAuth</string>
		<key>CFBundleURLSchemes</key>
		<array>
			<string>com.xamarin.traditional.standard.samples.oauth.providers.ios</string>
			<string>com.googleusercontent.apps.1093596514437-cajdhnien8cpenof8rrdlphdrboo56jh</string>
		</array>
		<key>CFBundleURLTypes</key>
		<string>Viewer</string>
	</dict>
</array>

[TODO Link to code]

NOTE: When editing Info.plist take care if it is auto-opened in the generic plist editor. Generic plist editor shows "CFBundleURLSchemes" as simple "URL Schemes". If user is using the plist editor to create the values and type in URL Schemes, it won't convert that to CFBundleURLSchemes. Switching to the xml editor and user will be able to see the difference.

Add code to intercept opening URL with registered custom scheme by implementing OpenUrl method override in AppDelegate:

public override bool OpenUrl
		(
			UIApplication application,
			NSUrl url,
			string sourceApplication,
			NSObject annotation
		)
{
	// Convert iOS NSUrl to C#/netxf/BCL System.Uri - common API
	Uri uri_netfx = new Uri(url.AbsoluteString);

	// load redirect_url Page (send it back to Xamarin.Auth)
	//	for Url parsing and raising Complete or Error events
	AuthenticationState.Authenticator.OnPageLoading(uri_netfx);

	return true;
}

[TODO Link to code]

4 Using identity

Xamarin.Forms support

Since version 1.5.0 Xamarin.Auth has built in support for Xamarin.Forms with 2 different implementations:

  • with platform specific Presenters (Dependency Service, Dependency Injection)

    This implementation has no dependencies on Xamarin.Forms, so it is in Xamarn.Auth nuget package.

  • with Custom Renderers

    This implementation dependens on Xamarin.Forms, so it is in separate nuget package - Xamarn.Auth.XamarinForms

More Information

https://developer.chrome.com/multidevice/android/customtabs

Installing Xamarin.Auth

Xamarin.Auth can be used (installed) through

  1. nuget package v >= 1.4.0.0
  2. project reference (source code)

NOTE: Xamarin Component for new nuget is not ready! 2017-03-28

Nuget package

Xamarin.Auth nuget package:

https://www.nuget.org/packages/Xamarin.Auth/

Current Version:

https://www.nuget.org/packages/Xamarin.Auth/1.3.2.7

Xamarin.Auth nuget package specification (nuspec):

Project reference

For debuging and contributing (bug fixing) contributions Xamarin.Auth can be used as source code for github repo:

Xamarin.Auth project (and folder structure) is based on Xamarin Components Team internal rules and recommendations.

Xamarin.Auth Cake script file is slightly modified to enable community members willing to help to compile Xamarin.Auth from source. Compilation is possible both on Windows and MacOSX. If working on both platforms Cake script expects artifacts to be build first on Windows and then on MacOSX, so nuget target (nuget packaging) will fail if script is executed

Installing Cake

Installing Cake is pretty easy:

Windows

    Invoke-WebRequest http://cakebuild.net/download/bootstrapper/windows -OutFile build.ps1
    .\build.ps1

Mac OSX 

    curl -Lsfo build.sh http://cakebuild.net/download/bootstrapper/osx
    chmod +x ./build.sh && ./build.sh

Linux

    curl -Lsfo build.sh http://cakebuild.net/download/bootstrapper/linux
    chmod +x ./build.sh && ./build.sh

Running Cake to Build Xamarin.Auth targets

Run cake with following command[s] to build libraries and nuget locally. For nuget run it 1st on Windows and then on Mac (Xamarin build bots do that and expect artifacts from Windows to be ready before packaging).

Running these targets is important for automatic package restore.

Windows

    tools\Cake\Cake.exe --verbosity=diagnostic --target=libs
    tools\Cake\Cake.exe --verbosity=diagnostic --target=nuget
    tools\Cake\Cake.exe --verbosity=diagnostic --target=samples

Mac OSX 

    mono tools/Cake/Cake.exe --verbosity=diagnostic --target=libs
    mono tools/Cake/Cake.exe --verbosity=diagnostic --target=nuget

Now, samples based on project references are ready to be used!

Component

Xamarin.Auth Component support is currently under development. It is "empty shell" component, i.e. component that uses nuget package as dependency and contains only samples, documentation and artwork.

Diverse

Some screenshots assembled with PlaceIt.