Development Information - Xamarin Forms Mobile application, utilizes MSAL library version 4.35.0 to authenticate against Azure AD and uses Brokered authentication flow utilizing the Microsoft Authenticator. This is coded in Visual Studio 2019 using C# and .Net 5.
Problem - Everything works in the Android emulator, but once deployed to an actual device, using Company Portal (Intune), the authentication piece fails with message:
Authentication Error [Android broker] The broker redirect URI is incorrect, it should be msauth://com.xxxxxx.xxxxxxx/xxxxxxxxxxxxxx Please visit https://aka.ms/Brokered-Authentication-for-Android for more details
I compared the redirect uri in the Azure portal to the one being displayed in the error message and they don't match, I don't know where it's getting this redirect uri value from?? Everything in the code base uses the callback uri specified in the Azure portal
I've worked through multiple MSDN documents, download example projects from GitHub, modified the Android Manifest file, etc. None of that seems to fix this issue. I am at my wits end with this. Here is an example of the Authentication code:
public static IPublicClientApplication PCA;
//OAuthSettings is a class containing my values to pass to the methods of the
//PublicClientApplicationBuilder
var builder = PublicClientApplicationBuilder
.Create(OAuthSettings.ApplicationId)
.WithTenantId(OAuthSettings.TenantId)
.WithBroker()
.WithRedirectUri(OAuthSettings.RedirectUri);
PCA = builder.Build();
try
{
var accounts = await PCA.GetAccountsAsync();
var silentAuthResult = await PCA
.AcquireTokenSilent(new string[] { "api://xxxxxxxxxxxxxx/.default" }, accounts.FirstOrDefault())
.ExecuteAsync();
AccessToken = new JwtSecurityToken(silentAuthResult.AccessToken);
//more code removed for brevity
}
catch (MsalUiRequiredException msalEx)
{
var windowLocatorService = DependencyService.Get<IParentWindowLocatorService>();
// Prompt the user to sign-in
var interactiveRequest = PCA.AcquireTokenInteractive(new string[] { "api://xxxxxxxxxxxxxxxxxxx/.default" });
//Used for Android and iOS
AuthUIParent = windowLocatorService?.GetCurrentParentWindow();
if (AuthUIParent != null)
{
interactiveRequest = interactiveRequest
.WithParentActivityOrWindow(AuthUIParent);
}
//
var interactiveAuthResult = await interactiveRequest.ExecuteAsync();
AccessToken = new JwtSecurityToken(interactiveAuthResult.AccessToken);
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" package="com.gpdgroup.GPDMobileAppTest" android:installLocation="auto" android:versionCode="7">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application android:label="mycompany.Android" android:theme="@style/MainTheme" android:usesCleartextTraffic="true" android:icon="@mipmap/icon" android:roundIcon="@mipmap/icon">
<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="msal{clientID}" android:host="auth" />
</intent-filter>
<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="msauth" android:host="com.mycompany.myapp" android:path="/{base64 hash}" />
</intent-filter>
</activity>
</application>
<!--Necessary to fix issue on authentication for level 30-->
<queries>
<package android:name="com.azure.authenticator" />
<package android:name="com.mycompany.myapp" />
<package android:name="com.microsoft.windowsintune.companyportal" />
<!-- Required for API Level 30 to make sure the app detect browsers
(that don't support custom tabs) -->
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
<!-- Required for API Level 30 to make sure the app can detect browsers that support custom tabs -->
<!-- https://developers.google.com/web/updates/2020/07/custom-tabs-android-11#detecting_browsers_that_support_custom_tabs -->
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
</manifest>
Screenshot of Azure Portal:
I also added an MSAL Authentication JSON file to the Resources folder of the Android project in a sub folder called raw called msal_default_config.json:
{
"client_id": "xxxxxxxxxxxxxxxxxxxxx",
"redirect_uri": "msauth://com.mycompany.myapp/{base64 url encoded signature hash}",
"broker_redirect_uri_registered": true,
"account_mode" : "SINGLE",
"authorities": [
{ "type": "AAD", "audience": { "type": "AzureADandPersonalMicrosoftAccount",
"tenant_id": "xxxxxxxxxxxxxxxxxx" }
} ]
}
And I also have this class for the Android project which inherits BrowserTabActivity class, called MsalActivity:
[Activity]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
DataHost = "auth",
DataScheme = "msal{clientID}")]
public class MsalActivity : BrowserTabActivity
{
}
