- Azure
- Xamarin
- Xamarin.Forms
- Xamarin.iOS
- Xamarin.Android
When developing a mobile application you often need an authentication system for your users. Create a new account for a specific usage this can be a barrier for some users. Your users will probably already have a Google, Facebook, Github or a Microsoft account. So why not using one of them instead of multiply the number of accounts ?
In this tutorial I’m going to show you how to authenticate your Xamarin applications using the Microsoft authentication system.
Here some advantages of using this technique:
IdToken
from the associated connection and use it with Open Id connect to authorize the access to a Web APIBefore being able to connect your users with their Microsoft account, we need to register an application on the Azure Portal
. This application is used to declare the kind of users account authorized to sign in with their Microsoft Account in your application.
So let’s start by going to the Azure Portal website, inside the left menu select Azure Active Directory then App registratons and click on New registration at the top of the screen.
Then :
Now if you open your application, inside the Overview tab you will find your Application (client) ID. This application id will be used to identify and authorize your Xamarin application, which is mandatory to authenticate the users using their Microsoft account.
We have our Azure application setup now, let’s move on to the next step : integrate the Microsoft authentication in our Xamarin application.
First of all, install the Microsoft.Identity.Client
Nuget to your shared code and your platforms projects.
Let’s create a new class called MicrosoftAuthService
where we will implements 4 methods:
public class MicrosoftAuthService : IMicrosoftAuthService
{
private readonly string ClientID = "REPLACE_WITH_YOUR_APP_ID";
private readonly string[] Scopes = { "User.Read" };
private readonly string GraphUrl = "https://graph.microsoft.com/v1.0/me";
private IPublicClientApplication publicClientApplication;
public void Initialize()
{
this.publicClientApplication = PublicClientApplicationBuilder.Create(ClientID)
.WithIosKeychainSecurityGroup("com.microsoft.adalcache")
.WithRedirectUri($"msal{ClientID}://auth")
.Build();
}
/// <summary>
/// This object is used to know where to display the authentication activity (for Android) or page.
/// </summary>
public static object ParentWindow { get; set; }
/// <summary>
/// Signin with your Microsoft account.
/// </summary>
public async Task<User> OnSignInAsync()
{
User currentUser = null;
var accounts = await this.publicClientApplication.GetAccountsAsync();
try
{
try
{
var firstAccount = accounts.FirstOrDefault();
var authResult = await this.publicClientApplication.AcquireTokenSilent(Scopes, firstAccount).ExecuteAsync();
currentUser = await this.RefreshUserDataAsync(authResult?.AccessToken).ConfigureAwait(false);
}
catch (MsalUiRequiredException ex)
{
// the user was not already connected.
try
{
var authResult = await this.publicClientApplication.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow(ParentWindow)
.ExecuteAsync();
currentUser = await this.RefreshUserDataAsync(authResult?.AccessToken).ConfigureAwait(false);
}
catch (Exception ex2)
{
// Manage the exception with a logger as you need
System.Diagnostics.Debug.WriteLine(ex2.ToString());
}
}
}
catch (Exception ex)
{
// Manage the exception with a logger as you need
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
return currentUser;
}
/// <summary>
/// Sign out with your Microsoft account.
/// </summary>
public async Task OnSignOutAsync()
{
var accounts = await this.publicClientApplication.GetAccountsAsync();
try
{
while (accounts.Any())
{
await this.publicClientApplication.RemoveAsync(accounts.FirstOrDefault());
accounts = await this.publicClientApplication.GetAccountsAsync();
}
}
catch (Exception ex)
{
// Manage the exception with a logger as you need
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
/// <summary>
/// Refresh user date from the Graph api.
/// </summary>
/// <param name="token">The user access token.</param>
/// <returns>The current user with his associated informations.</returns>
private async Task<User> RefreshUserDataAsync(string token)
{
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, this.GraphUrl);
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
User currentUser = null;
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
currentUser = JsonConvert.DeserializeObject<User>(json);
}
return currentUser;
}
}
Let’s explain this class:
First we need to declare the ClientID
that we retrieved from the Azure Portal. Then the Initialize
method will init the PublicClientApplication
with our Application (client) ID. For iOS we need to call the WithIosKeychainSecurityGroup
method to let the application access to the Keychain of the device.
The OnSignInAsync
method will automatically display the Microsoft authentication webview. We first check if an account is already present on the device if it’s the case, the account will be automatically suggested to the user. We pass a Scope that represent the list of elements we want to get access, here we just want to read the user informations so we use : User.Read
The OnSignOutAsync
method remove all accounts connected on the device.
Finally the RefreshUserDataAsync
will call the Graph Api from Microsoft to get the details about the user account.
I will recommend you to create the associated interface for this service to be able to use dependency injection in a real project.
For Android you need to do the 3 following steps:
First one, go to your MainActivity.cs
and override the OnActivityResult
method and add this line to it:
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
This will ensure that the control goes back to MSAL (Microsoft Authentication Library) when the interactive portion of the authentication flow will be finished.
Second step, add this line to the end of your OnCreate
method, this will ensure that the authentication flows occur in the context of the current activity.
MicrosoftAuthService.ParentWindow = this;
Last step for Android, go to the AndroidManifest.xml
and declare a new activity like this:
<application android:label="MicrosoftDemoProject.Android">
<activity android:name="microsoft.identity.client.BrowserTabActivity">
<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:scheme="msalREPLACE_WITH_YOUR_APP_ID" android:host="auth" />
</intent-filter>
</activity>
</application>
This activity is used to display the Microsoft authentication page in a specific activity. Be sure to setup the Application (client) ID correctly in it.
For the iOS project you need to follow these 3 steps:
First of all go to the AppDelegate.cs
class and override the following method:
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return true;
}
Like we did in the Android project, this line will ensure the proper functioning of MSAL.
Next step we need to enable the Keychain Groups inside the Entitlements.plist
and specify a KeyChain Group with com.microsoft.adalcache this will allow the application to access the Keychain of the device.
Then open the project settings and in the iOS Bundle Signing select the Entitlements.plist inside the Custom Entitlements property.
If you don’t do that correctly you will get this kind of error:
Microsoft.Identity.Client.MsalClientException: The application cannot access the iOS keychain for the application publisher (the TeamId is null). This is needed to enable Single Sign On between applications of the same publisher. This is an iOS configuration issue. See https://aka.ms/msal-net-enable-keychain-access for more details on enabling keychain access.
Final step go to the Info.plist
and add these lines:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.companyname.MicrosoftDemoProject</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msalREPLACE_WITH_YOUR_APP_ID</string>
</array>
</dict>
</array>
This will used when the application will open the MSAL authentication URL. Don’t forget to setup the Application (client) ID correctly in it and change the CFBundleURLName
with the Bundle identifier of your project.
I created a complete and simple example of this code using dependency injection with MvvmLightLibs
to show you a complete example with a simple architecture.
You will find full source code in this Github repository.
Happy coding!
You liked this tutorial? Leave a star in the associated Github repository!