i am trying to make Azure AD B2C work in my xamarin app. to check if we already are logged in i am using a code like below.
public async Task<bool> IsLoggedIn()
{
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
if (accounts != null)
{
return accounts.Any();
}
return false;
}
}
My code on Start looks like this
protected async override void OnStart()
{
var authenticationService = Container.Resolve<IAuthenticationService>();
bool isLoggedIn;
isLoggedIn = await authenticationService.IsLoggedIn();
if (isLoggedIn)
{
var cachingService = Container.Resolve<ICachingService>();
AppUser = await authenticationService.Login(cachingService.CurrentMode);
await NavigationService.NavigateAsync("http://www.xxxx.com/root/navigation/main");
}
else
{
await NavigationService.NavigateAsync("http://www.xxxx.com/navigation/login");
}
}
}
if i just return false from IsLoggedIn it shows the login page properly. But calling
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
seems to be problematic.
i get exception (sometimes) that System.NullReferenceException: Object reference not set to an instance of an object
but looking at App object in "QuickWatch" i see PAC object being properly populated.
UPDATE App.cs constructor looks like this
public static PublicClientApplication PCA = null;
public App(IPlatformInitializer initializer = null) : base(initializer)
{
PCA = new PublicClientApplication(GlobalSetting.Instance.ClientID, GlobalSetting.Instance.AuthoritySignUpSignIn);
PCA.RedirectUri = $"msal{GlobalSetting.Instance.ClientID}://auth";
}
my login method looks like this
public async Task<User> Login(string mode)
{
IEnumerable<IAccount> accounts = await App.PCA?.GetAccountsAsync();
AuthenticationResult ar;
try
{ //get token from cache.
ar = await App.PCA?.AcquireTokenSilentAsync(GlobalSetting.Instance.Scopes, GetAccountByPolicy(accounts, GlobalSetting.Instance.PolicySignUpSignIn), GlobalSetting.Instance.AuthoritySignUpSignIn, false);
}
catch (MsalUiRequiredException ex)
{
// get token from interaction.
ar = await App.PCA?.AcquireTokenAsync(GlobalSetting.Instance.Scopes, GetAccountByPolicy(accounts, GlobalSetting.Instance.PolicySignUpSignIn), App.UiParent);
}
//fetch token and make actual user object.
return new User
{
Id = _cachingService.LoggedInUserId,
Name = "Jessica Doe",
ProfilePicUrl = "https://content-static.upwork.com/uploads/2014/10/01xxx27/profilephoto1.jpg",
BusinessProfile = _userService.GetBusinessProfile(_cachingService.LoggedInUserId),
ProfileVariables = _userService.GetUserProfileVariables(_cachingService.LoggedInUserId),
Settings = _userService.GetSettings(_cachingService.LoggedInUserId)
};
}
it works when i dont call AcquireTokenSilentAsync and just send a fake User object and does not work when i call AcquireTokenSilentAsync. ar object gets populated, it navigates to the main page hits it's view model constructor but but shows a blank page.
i have also tried diffrent versions of MSAL. now on the latest version.
UPdate2
drilled down to this exception
{Microsoft.Identity.Client.MsalClientException: The application does not have keychain access groups enabled in the Entitlements.plist. As a result, there was a failure to save to the iOS keychain. The keychain access group '3G3LMCD5R.com.microsoft.adalcache' is not enabled in the Entitlements.plist. See https://aka.ms/msal-net-enable-keychain-groups for more details on enabling keychain access groups and entitlements. at Microsoft.Identity.Core.iOSTokenCacheAccessor.Save (System.String account, System.String service, System.String generic, System.Int32 type, System.String value) [0x00052] in :0 at Microsoft.Identity.Core.iOSTokenCacheAccessor.SaveAccessToken (Microsoft.Identity.Core.Cache.MsalAccessTokenCacheItem item) [0x00028] in :0 at Microsoft.Identity.Core.Telemetry.TelemetryTokenCacheAccessor.SaveAccessToken (Microsoft.Identity.Core.Cache.MsalAccessTokenCacheItem item) [0x00000] in :0 at Microsoft.Identity.Core.Telemetry.TelemetryTokenCacheAccessor.SaveAccessToken (Microsoft.Identity.Core.Cache.MsalAccessTokenCacheItem item, Microsoft.Identity.Core.RequestContext requestContext) [0x0002a] in :0 at Microsoft.Identity.Client.TokenCache.SaveAccessAndRefreshToken (Microsoft.Identity.Core.Instance.IValidatedAuthoritiesCache validatedAuthoritiesCache, Microsoft.Identity.Core.Instance.IAadInstanceDiscovery aadInstanceDiscovery, Microsoft.Identity.Client.Internal.Requests.AuthenticationRequestParameters requestParams, Microsoft.Identity.Core.OAuth2.MsalTokenResponse response) [0x00143] in :0 at Microsoft.Identity.Client.Internal.Requests.RequestBase.CacheTokenResponseAndCreateAuthenticationResult (Microsoft.Identity.Core.OAuth2.MsalTokenResponse msalTokenResponse) [0x001b4] in :0 at Microsoft.Identity.Client.Internal.Requests.InteractiveRequest+d__9.MoveNext () [0x00168] in :0 --- End of stack trace from previous location where exception was thrown --- at Microsoft.Identity.Client.Internal.Requests.RequestBase+d__28.MoveNext () [0x00160] in :0 --- End of stack trace from previous location where exception was thrown --- at Microsoft.Identity.Client.PublicClientApplication+d__24.MoveNext () [0x000ef] in :0 --- End of stack trace from previous location where exception was thrown --- at Microsoft.Identity.Client.PublicClientApplication+d__17.MoveNext () [0x000ac] in :0 --- End of stack trace from previous location where exception was thrown --- at CDThat.Services.AzureADB2CAuthenticationService+d__3.MoveNext () [0x000fc] in C:\CDthatbest\CDThat\Services\AzureADB2CAuthenticationService.cs:45 --- End of stack trace from previous location where exception was thrown --- at CDThat.ViewModels.LoginPageViewModel+d__8.MoveNext () [0x0003c] in C:\CDthatbest\CDThat\ViewModels\LoginPageViewModel.cs:56 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_0 (System.Object state) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.2.1.11/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1023 at Foundation.NSAsyncSynchronizationContextDispatcher.Apply () [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.2.1.11/src/Xamarin.iOS/Foundation/NSAction.cs:178 at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr) at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.2.1.11/src/Xamarin.iOS/UIKit/UIApplication.cs:79 at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0002c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.2.1.11/src/Xamarin.iOS/UIKit/UIApplication.cs:63 at CDThat.iOS.Application.Main (System.String[] args) [0x00014] in C:\CDthatbest\CDThat.iOS\Main.cs:16 ErrorCode: missing_entitlements}