page_type: sample description: "This is a simple Xamarin Forms app showcasing how to use MSAL to authenticate users via Azure Active Directory B2C." languages:
This is a simple Xamarin Forms app showcasing how to use MSAL to authenticate users via Azure Active Directory B2C, and access an ASP.NET Web API with the resulting token. For more information on Azure B2C, see the Azure AD B2C documentation.
We have renamed the default branch to main. To rename your local repo follow the directions here.
To run this sample you will need:
If you don't have an Azure AD B2C tenant, you can follow those instructions to create one. If you just want to see the sample in action, you don't need to create your own tenant as the project comes with some settings associated to a test tenant and application; however it is highly recommend that you register your own app and experience going through the configuration steps below.
From your shell or command line:
git clone https://github.com/Azure-Samples/active-directory-b2c-xamarin-native.git
You can also modify the sample to use your own Azure AD B2C tenant. First, you'll need to create an Azure AD B2C tenant by following these instructions.
IMPORTANT: if you choose to perform one of the optional steps, you have to perform ALL of them for the sample to work as expected.
This sample uses three types of policies: a unified sign-up/sign-in policy, a profile editing policy, and a reset password policy. Create one policy of each type by following the instructions here. You may choose to include as many or as few identity providers as you wish.
b2clogin.com
.If you already have existing policies in your Azure AD B2C tenant, feel free to re-use those. No need to create new ones just for this sample.
This sample calls an API at https://fabrikamb2chello.azurewebsites.net which has the same code as the sample Node.js Web API with Azure AD B2C. You'll need your own API or at the very least, you'll need to register a Web API with Azure AD B2C so that you can define the scopes that your single page application will request access tokens for.
Your web API registration should include the following information:
https://myapi
.demoapi
, this is used to construct the scopes that are configured in you single page application's code.read
name.Now you need to register your native app in your B2C tenant, so that it has its own Application ID. Don't forget to grant your application API Access to the web API you registered in the previous step.
Your native application registration should include the following information:
msal<Application Id>://auth
.UserDetailsClient\UserDetailsClient.Core\Features\LogOn\B2CConstants.cs
file.public static string Tenant
and replace the value with your tenant name.public static string TentantRedirectUrl
and replace the value with your tenant redirect url. In the past, login.microsoftonline.com
was used, now you should be using {tenant_name}.b2clogin.com
. For more information on changing redirect URL's see here.public static string ClientID
and replace the value with the Application ID from Step 5.public static string PolicyX
and replace the names of the policies you created in Step 3.public static string[] Scopes
and replace the scopes with those you created in Step 4.UserDetailsClient.iOS\info.plist
file in a text editor (opening it in Visual Studio won't work for this step as you need to edit the text)In the URL types, section, add an entry for the authorization schema used in your redirectUri.
<array>
<dict>
<key>CFBundleURLName</key>
<string>active-directory-b2c-xamarin-native</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msal[Enter_the_Application_Id_Here]</string>
</array>
<key>CFBundleTypeRole</key>
<string>None</string>
</dict>
</array>
where [Enter_the_Application_Id_Here]
is the identifier you copied in step 2. Save the file.
UserDetailsClient.Droid\MsalActivity.cs
file.[Enter_the_Application_Id_Here]
with the identifier you copied in step 2. [Activity]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
DataHost = "auth",
DataScheme = "msal[Enter_the_Application_Id_Here]")]
public class MsalActivity : BrowserTabActivity
{
}
If you have issues with the Android emulator, please refer to this document for instructions on how to ensure that your emulator supports the features required by MSAL.
The structure of the solution is straightforward. All the application logic and UX reside in UserDetailsClient (portable).
MSAL's main primitive for native clients, PublicClientApplication
, is initialized as a static variable in App.cs.
At application startup, the main page attempts to get a token without showing any UX - just in case a suitable token is already present in the cache from previous sessions. This is the code performing that logic:
protected override async void OnAppearing()
{
UpdateSignInState(false);
// Check to see if we have a User in the cache already.
try
{
AuthenticationResult ar = await App.PCA.AcquireTokenSilent(App.Scopes,
GetUserByPolicy(App.PCA.Users, App.PolicySignUpSignIn))
.WithAuthority(App.PolicySignUpSignIn)
.ExecuteAsync();
UpdateUserInfo(ar);
UpdateSignInState(true);
}
catch (Exception)
{
// Doesn't matter, we go in interactive mode
UpdateSignInState(false);
}
}
If the attempt to obtain a token silently fails, we do nothing and display the screen with the sign in button. When the sign in button is pressed, we execute the same logic - but using a method that shows interactive UX:
var windowLocatorService = DependencyService.Get<IParentWindowLocatorService>();
AuthenticationResult ar = await App.PCA.AcquireTokenInteractive(App.Scopes)
.WithAccount(GetUserByPolicy(App.PCA.Users,
App.PolicySignUpSignIn)
.WithParentActivityOrWindow(() => windowLocatorService?.GetCurrentParentWindow()))
.ExecuteAsync();
The Scopes
parameter indicates the permissions the application needs to gain access to the data requested through subsequent web API call (in this sample, encapsulated in OnCallApi
). Scopes should be input in the following format: https://{tenant_name}.onmicrosoft.com/{app_name}/{scope_value}
The .WithParentActivityOrWindow()
is used in Android to tie the authentication flow to the current activity, and is ignored on all other platforms. That code ensures that the authentication flows occur in the context of the current activity.
The sign out logic is very simple. In this sample we have just one user, however we are demonstrating a more generic sign out logic that you can apply if you have multiple concurrent users and you want to clear up the entire cache.
var accounts = await App.GetAccountsAsync();
foreach (var account in accounts.ToArray())
{
App.PCA.Remove(account);
}
The platform specific projects require only a couple of extra lines to accommodate for individual platform differences.
UserDetailsClient.Droid requires one extra line in the MainActivity.cs
file.
In OnActivityResult
, we need to add
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
That line ensures that control goes back to MSAL once the interactive portion of the authentication flow ended.
UserDetailsClient.iOS only requires one extra line, in AppDelegate.cs. You need to ensure that the OpenUrl handler looks as the snippet below:
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return true;
}
Once again, this logic is meant to ensure that once the interactive portion of the authentication flow is concluded, the flow goes back to MSAL.
In order to make the token cache work and have the AcquireTokenSilentAsync
work multiple steps must be followed :
Entitlements.plist
file and specify in the Keychain Groups your bundle identifier.Entitlements.plist
file for the Custom Entitlements field.For more information on Azure B2C, see the Azure AD B2C documentation homepage.