Easy Xamarin Essentials with Web Authenticator

Authentication is an important part of today’s mobile applications, but securely implementing authentication in a mobile app can be a daunting task. In this article, you will learn how to create a basic cross-platform application with Xamarin.Forms and use the WebAuthenticator class from Xamarin.Essentials together with Okta to quickly and easily add user login to your mobile app.

To continue you will need:

  • A basic knowledge of C#
  • Visual Studio 2019
  • An Okta Developer Account (free forever, to handle your OAuth needs)
  • An Android or iPhone device or an emulator for testing (For the article, we show Android as an example but this will work for either platform)

Create a Xamarin.Forms App with Xamarin.Essentials

Xamarin is a framework from Microsoft for building cross-platform mobile apps from one shared source code, written in C#, and compiled to each platform’s runtime. Xamarin.Forms is an abstraction on that, enabling developers to share the UI code as well. Xamarin.Essentials is a NuGet package providing cross-platform APIs for accessing and using native platform capabilities. In this article I will show you how to build a simple Xamarin.Forms app and add authentication to it.

Xamarin.Forms is now included in Visual Studio! Create a new project by clicking File>New Project in Visual Studio, select Mobile App (Xamarin.Forms), and click Next. Name the app OktaAuth and click Create. On the next window, select Blank and click OK.

Configure your project

Visual Studio will automatically create a solution with three projects: OktaAuth.Android for Android, OktaAuth.iOS for iOS, and OktaAuth for shared code and user interface. The projects already include Xamarin.Essentials out of the box - however, the included version doesn’t have the WebAuthenticator class, so you will need to update it to the latest available version which, as of the publish date of this post, is 1.5.3.2

Now, run the app on your attached mobile device (or in the simulator) and you should see a screen like this:

Run the Xamarin app

Next, it’s time to secure your users login!

Xamarin.Essentials Auth Flow with an External Identity Provider

I will use Okta to easily and securely implement user authentication so that I don’t have to implement it from scratch or roll my own identity management. Okta supports user authentication, multi-factor authentication, social authentication as well as all OpenID connect flows out of the box—so it can take care of all the scenarios you might ever need.

In the sample app, I will use Okta’s browser-based OpenID Connect flow to securely authenticate the user via the native browser installed on the device. Using an external browser is the most secure way to authenticate and allows you to log in automatically if you are already signed in the browser. Also, you won’t need to store the ‘client secret’` in your mobile app. When you log in, the browser will redirect you back to your Xamarin app using the redirect URI and pass the requested token as a parameter.

OIDC app flow

The WebAuthenticator class from Xamarin.Essentials library simplifies implementing this flow and takes care of launching the browser, handling redirect, and parsing received parameters for you.

Add Authentication with Xamarin.Essentials and Okta

To get started, log in to your Okta Developer Account via the URL you are emailed after signing up, to access your org’s portal dashboard. Once you log in, make sure to note your Org URL from the upper right corner of the screen:

Okta org URL

Now create a new application. Click Applications in the top menu and then Add Application. Select Native and click Next.

Okta native app selection

Enter a name (I will use OktaAuth again), check Implicit (Hybrid) at the bottom of the screen, and click Done.

Okta create app details

Switch back to Visual Studio and add a login and logout button to the app. In the shared OktaAuth project, double-click the MainPage.xaml file and replace its content with this:

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="OktaAuth.MainPage">
  <StackLayout VerticalOptions="Center">
    <Label Text="Welcome to Xamarin.Forms!" x:Name="WelcomeLabel"
      HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
    <Button x:Name="LoginButton" Text="Log in with Okta"
      HorizontalOptions="Center" Clicked="LoginButtonClicked"/>
    <Button x:Name="LogoutButton" Text="Log out"  IsVisible="False"
      HorizontalOptions="Center" Clicked="LogoutButtonClicked"/>
  </StackLayout>
</ContentPage>

In the MainPage.xaml.cs file add empty event handlers for the login and logout buttons:

private async void LoginButtonClicked(object sender, EventArgs e)
{
}

private void LogoutButtonClicked(object sender, EventArgs e)
{
}

Next, add a class to the project and name it OktaConfiguration. This class will hold configuration data that you need to pass to Okta and should look like this:

public class OktaConfiguration
{
  public const string ClientId = "{clientId}";

  public const string OrganizationUrl = "https://{yourOktaDomain}";

  public const string Callback = "com.okta.{yourOktaAccountNameOnly i.e. 'dev-12345'}:/callback";

  public const string CallbackScheme = "com.okta.{yourOktaAccountNameOnly i.e. 'dev-12345'}";
}

Copy the Login redirect URI from your app configuration to the Callback field and paste it into the CallbackScheme (excluding the :/callback part). Copy ClientId value to the ClientId field too.

IOS and Android Setup for Xamarin WebAuthenticator

Before you use the WebAuthenticator class, you need to perform each platform-specific setup. For Android, add the following class to the OktaAuth.Android project:

[Activity(NoHistory = true, LaunchMode = LaunchModeSingleTop)]
[IntentFilter(new[] { Android.Content.Intent.ActionView ,
  Categories = new[] { Android.Content.IntentCategoryDefault, Android.Content.IntentCategoryBrowsable },
  DataScheme = OktaConfiguration.CallbackScheme)]
public class WebAuthenticationCallbackActivity : XamarinEssentials.WebAuthenticatorCallbackActivity
{
  protected override void OnResume()
  {
    base.OnResume();
    Xamarin.Essentials.Platform.OnResume();
  }
}

For iOS, open the Info.plist file, go to the Advanced tab, click Add Url Type, and enter CallbackScheme value in the URL Schemes field.

Xamarin info.plist platform setup

You also need to override the OpenUrl method in the AppDelegate class:

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);
}

Next, add a LoginService class that will build the url with required parameters and also parse the ID token returned by Okta. Paste this code in the LoginService class:

class LoginService
{
  private string codeVerifier;
  private const string IDToken = "id_token";
  private const string CodeChallengeMethod = "S256";

  public string BuildAuthenticationUrl()
  {
    var state = CreateCryptoGuid();
    var nonce = CreateCryptoGuid();
    var codeChallenge = CreateCodeChallenge();

    return $"{OktaConfiguration.OrganizationUrl}/oauth2/default/v1/authorizeresponse_type={IDToken}ope=openid%20profile&redirect_uri={OktaConfigurationCallback}&client_id={OktaConfiguration.ClientId}state=tate}&code_challenge{codeChallenge}&code_challenge_method={CodeChallengeMethod}&nonce={nonce}";
  }
  
  private string CreateCryptoGuid()
  {
    using (var generator = RandomNumberGenerator.Create())
    {
      var bytes = new byte[16];
      generator.GetBytes(bytes);
      return new Guid(bytes).ToString("N");
    }
  }

  private string CreateCodeChallenge()
  {
    codeVerifier = CreateCryptoGuid();
    using (var sha256 = SHA256.Create())
    {
      var codeChallengeBytes = sha256.ComputeHash(Encoding.UTF8.GetByte(codeVerifier));
      return Convert.ToBase64String(codeChallengeBytes);
    }
  }  
  
  public JwtSecurityToken ParseAuthenticationResult(WebAuthenticatorResultauthenticationResult)
  {
    var handler = new JwtSecurityTokenHandler();
    var token = handler.ReadJwtToken(authenticationResult.IdToken);
    return token;
  }
}

The code in the BuildAuthenticationUrl method builds the URL required by the auth code grant flow with PKCE. The base URL, when using Okta as the authorization server, is https://${yourOktaDomain}/oauth2/default/v1/authorize. The method then appends client_Id, response_type and scope parameters, sets the redirect_uri to the login redirect URI from the app configuration, and sets other parameters as required by the PKCE flow.

The ParseAuthenticationResult method parses the jwt IdToken returned by Okta into a JwtSecurityToken object that contains all the claims from the token.

You are now ready to use the WebAuthenticator class to start the login flow.

Go to the MainPage.Xaml.cs file and add and initialize LoginService field:

private readonly LoginService loginService = new LoginService();

Next, replace the LoginButtonClicked method with this:

private async void LoginButtonClicked(object sender, EventArgs e)
{
  try
  {
    var callbackUrl = new Uri(OktaConfiguration.Callback);
    var loginUrl = new Uri(loginService.BuildAuthenticationUrl());

    var authenticationResult = await WebAuthenticator.AuthenticateAsync(loginUrl, callbackUrl)
    var token = loginService.ParseAuthenticationResult(authenticationResult);

    var nameClaim = token.Claims.FirstOrDefault(claim => claim.Type == "given_name")
    if (nameClaim != null)
    {
      WelcomeLabel.Text = $"Welcome to Xamarin.Forms {nameClaim.Value}!";
      LogoutButton.IsVisible = !(LoginButton.IsVisible = false);
    }
  }
  catch (TaskCanceledException)
  {
      //User closed browser
  }
}

When the login button is clicked, it builds the authentication url and passes it and the callback url to the WebAuthenticator.AuthenticateAsync() method. The WebAuthenticator.AuthenticateAsync() method will launch an external browser and, when I log in, redirects me back to the app passing the token returned by Okta. It then extracts the given_name claim from the parsed claims and displays its value in the WelcomeLabel.

The logout button will simply reset the app to its initial state:

private void LogoutButtonClicked(object sender, EventArgs e)
{
  WelcomeLabel.Text = "Welcome to Xamarin.Forms!";
  LogoutButton.IsVisible = !(LoginButton.IsVisible = true);
}

Now run the app, click the Login with Okta button, log in to your Okta account and you will see a screen similar to this:

Run Xamarin app final

That’s it!

Learn More About Xamarin, OpenID Connect, and Okta

I hope the tutorial was interesting to you and that you enjoyed it. You can get the full source code of the project from GitHub. For more Xamarin and Okta articles check out these posts:

Okta’s OpenID Connect Primer in three parts:

Make sure to follow us on Twitter and subscribe to our YouTube Channel so that you never miss any awesome content!