DEV Community

Cover image for Using AWS Cognito with Xamarin Forms
Pieter van der Westhuizen
Pieter van der Westhuizen

Posted on

Using AWS Cognito with Xamarin Forms

In this post, I'll show you how to quickly and easily set up user authentication for your Xamarin Forms app using Amazon Cognito.

AWS Cognito is a user identity management solution by Amazon. It is a really easy way to add authentication to your application without having to worry about building and managing your own identity/authentication solution.

Xamarin Forms is an open-source cross-platform framework that you can use to create applications for Android, iOS and Windows.

Setting up an AWS Cognito user pool

First, we will need to create a user pool in AWS Cognito, which we'll use to create users and an App client. Head over to your AWS Cognito console and click on the "Manage User Pools" button.

image

Click the "Create a user pool" button, in the top-right corner of the next page. Next, enter a name for and choose the "Review defaults" option
image

On the next page, you can review the default options (I'll leave you to experiment with the different settings on your own) and scroll down to App clients.

image

Click on the "Add app client..." link and on the next page, click "Add an app client".

Next, only enter an App client name (We'll use "My Xamarin App" and keep all the options with their default values, scroll down and click "Create app client"
image

Click the "Return to pool details" and finally click on the "Create pool" button.

Creating a new user

Before we can log in, we first need to create a user. To do this, click on Users and groups under General settings and click the "Create user" button.
image
Complete the form, by entering a valid email address (This will be needed shortly) and make sure to tick the Send an invitation to this new user? and Email checkboxes.
image

With the user created, we need to configure the App client to allow the user to sign in.

Configuring the App client

Click on App client settings under App integration. Check the Cognito User Pool checkbox and complete the Callback URL(s) and Sign out URL(s). These can be any valid web address for now, we'll change them a bit later on for use with our Xamarin app.

Next, check the Implicit grant OAuth flow and select the email, openid and profile OAuth scopes (The scopes won't be super important for this demo, but is when you integrate with your own API, etc.)

image

Choose a domain name

With the App client configured, you need to choose a domain name. Click on Doman name under App integration and enter any domain prefix you prefer and check if it is available by clicking on the Check availability button.

If your domain name is available, save the changes, and move onto customizing the UI for the sign-in page.

Image3

Customizing the sign-in UI

Customizing the UI is an optional step, but it is a nice way to make the UI fit in with your color scheme. Not much need to change with the default style, the only change is to add a custom logo.
image

Testing the sign-in UI

Save your changes and head back to App client settings where you will notice that we now have the Launch Hosted UI link at the bottom of the page:
image

Clicking on the Launch Hosted UI link will open the sign-in page in a separate browser tab and you should see something similar to the following:
image

Go ahead and sign in using the credentials for the user we have created earlier. You'll be prompted to specify a new password, remember this password as we'll use it shortly to log in via our Xamarin app.

The Xamarin Forms App

I'm not going to walk you through the process of creating the Xamarin Forms app as I'm assuming you are familiar with the process. The app will not be very complicated and will consist of only one view/page.

Prism Library

I'm a fan of Prism for my Xamarin Forms apps, and will use it for this one, but the code will still work with standard Xamarin Forms or any other MVVM framework.
I'm using the Prism Template Pack to create as basic Xamarin.Forms Prism Blank App. This project template will stub out all the necessary files we need for this example.

Xamarin Essentials

First, add the Xamarin.Essentials NuGet Package to your projects. If you're using MVVM (Like we're doing in this example), you'll ideally want to install the Xamarin.Essentials.Interfaces NuGet Package

Android Project Changes

In the Android project, add a new class called WebAuthenticationCallbackActivity and add the following code to it:

using Android.App;
using Android.Content.PM;

namespace XFCognito.Droid
{
    [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop)]
    [IntentFilter(new[] {Android.Content.Intent.ActionView},
        Categories = new[] {Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable},
        DataScheme = "myxfcognitoapp")]
    public class WebAuthenticationCallbackActivity
        : Xamarin.Essentials.WebAuthenticatorCallbackActivity
    {

    }
}
Enter fullscreen mode Exit fullscreen mode

Make note of the DataScheme value, myxfcognitoapp, we are going to need this later.

AndroidManifest.xml
If you're targeting Android 11, you'll need to add the following to AndroidManifest.xml:

<queries>
  <intent>
    <action android:name="android.support.customtabs.action.CustomTabsService" />
  </intent>
</queries>
Enter fullscreen mode Exit fullscreen mode

iOS Project Changes

Info.plist
In your iOS project add the following to Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>myxfcognitoapp</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myxfcognitoapp</string>
    </array>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
  </dict>
</array>
Enter fullscreen mode Exit fullscreen mode

Note that we're using the same value(myxfcognitoapp), that we've used for the DataScheme value in Android for CFBundleURLName and CFBundleURLSchemes.

AppDelegate.cs
Override the OpenUrl and ContinueUserActivity methods in the AppDelegate class with the following:

public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
    if (Xamarin.Essentials.Platform.OpenUrl(app, url, options))
        return true;

    return base.OpenUrl(app, url, options);
}

public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, 
    UIApplicationRestorationHandler completionHandler)
{
    if (Xamarin.Essentials.Platform.ContinueUserActivity(application, userActivity, completionHandler))
        return true;

    return base.ContinueUserActivity(application, userActivity, completionHandler);
}

Enter fullscreen mode Exit fullscreen mode

The Xamarin.Essentials documentation is an excellent resource if you need more information on how the Web Authenticator works. I can highly recommend it.

Shared Project Changes

App.xaml.cs
Open the App.xaml.cs file and change the RegisterTypes method to the following:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterSingleton<IWebAuthenticator, WebAuthenticatorImplementation>();

    containerRegistry.RegisterForNavigation<NavigationPage>();
    containerRegistry.RegisterForNavigation<MainPage, MainPageViewModel>();
}
Enter fullscreen mode Exit fullscreen mode

All we're doing is registering the WebAuthenticator so that we can inject it into our ViewModel and setting up the Prism navigation.

MainPageViewModel.cs
Next, open the MainPageViewModel.cs class in the ViewModels folder. Change the code to the following:

using Prism.Commands;
using Prism.Navigation;
using System;
using System.Threading.Tasks;
using Xamarin.Essentials.Interfaces;

namespace XFCognito.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        private readonly IWebAuthenticator _webAuthenticator;

        private string _accessToken;
        public string AccessToken
        {
            get => _accessToken;
            set => SetProperty(ref _accessToken, value);
        }

        private DelegateCommand _loginCommand;
        public DelegateCommand LoginCommand => _loginCommand ?? (_loginCommand = new DelegateCommand(ExecuteLoginCommand));

        public MainPageViewModel(INavigationService navigationService, IWebAuthenticator webAuthenticator) : base(navigationService)
        {
            _webAuthenticator = webAuthenticator;
            Title = "AWS Cognito & Xamarin Forms";
        }

        async void ExecuteLoginCommand()
        {
            try
            {
                var results = await _webAuthenticator.AuthenticateAsync(
                    new Uri("https://myxamarinapp.auth.us-east-1.amazoncognito.com/login?client_id=4jlfe2iki0ucn32uc44clmib3d&response_type=token&scope=email+openid+profile&redirect_uri=myxfcognitoapp://"),
                    new Uri("myxfcognitoapp://"));

                AccessToken = results?.AccessToken;
            }
            catch (TaskCanceledException  e)
            {
                AccessToken = "You've cancelled.";
            }
        }
    }

}

Enter fullscreen mode Exit fullscreen mode

In the code above, we've created a property that will hold the AccessToken we get back from AWS Cognito, we've also added a LoginCommand that calls the Xamarin Essentials WebAuthenticator's AuthenticateAsync method.

The AuthenticateAsync method takes two parameters, the first is the URL to the AWS Hosted UI, you can get this by copying the URL that opens when clicking the Launch Hosted UI link in AWS Cognito's App client settings.
The second parameter is the DataScheme value (myxfcognitoapp) that we've used previously with a colon and two forward slashes appended.

Final Changes

Go back to the App client settings in AWS Cognito and change the Callback URL(s) to the DataScheme value, in the following format:

myxfcognitoapp://

image

The app in action

When running the app on Android, the first view will be the MainPage.
image

Tapping on the Login button, you'll be taken to the AWS Cognito Hosted Login page.
image

After entering your credentials and signing in, the app will navigate back to the MainPage and your AccesToken will be displayed.
image

This AccessToken can now be used to make any authenticated API calls you need.

The experience on iOS is similar:

Thank you for reading. Until next time, keep coding!

Full app source code is available on GitHub: https://github.com/Pietervdw/xamarinforms-awscognito

Top comments (7)

Collapse
 
jerryno6 profile image
jerryno6 • Edited

Thank you for the post, I preciate this. When I followed this guide, I encoutered an issue that it did not work on Xamarin UWP, so I forked your git source code and made an improvement for it to work with UWP at this url github.com/jerryno6/xamarinforms-a.... I hopw anyone meet this issue, they could know how to handle it easily

Collapse
 
alfredconlan profile image
Alfred Conlan

Great tutorial! However, the project I built only has a label on the MainPage and I don't see where in the article we might have changed it. What am I doing wrong?

Collapse
 
pietervdw profile image
Pieter van der Westhuizen • Edited

Hi Alfred,

Thank you for reading the post! Glad it's useful.
The UI for the MainPage only consist of a one button and a label. When tapping the button you are then taken to the AWS Cognito UI and after entering your credentials you are redirected back to the MainPage and the label should show the access token.

The LoginCommand does most of the work and you can see the code that gets executed in the ExecuteLoginCommand() method. Take a look at the code for this post on GitHub: github.com/Pietervdw/xamarinforms-...

Hope this helps! If not, feel free to ask me more questions.

-P

Collapse
 
alfredconlan profile image
Alfred Conlan

Thank you Pieter!

Collapse
 
pvanroos profile image
Paul VanRoosendaal

How can you make this work when you add an idp like Google? Because the Google Dev Console won't allow 'myxfcognitoapp://' as as redirect_uri.

Collapse
 
natarajan_arunkumar_7e5ac profile image
Natarajan Arunkumar

How to work on signout or logout functionality on aws cognito? @pietervdw

Collapse
 
cinmay2014 profile image
Yidong Zhu

Can we just redirect to app's second page after we login? How to do it?