4

I am using Xamarin.Forms and trying to use Microsoft Graph API following this tutorial.

This works perfectly in an iOS simulator, but when I try on my actual device, I cannot log in. When I click on the login button on my WelcomePage.xaml, it does absolutely nothing....is there something I'm missing?

This is my SignIn Method:

public async Task SignIn()
{

    var scopes = OAuthSettings.Scopes.Split(' ');

    // First, attempt silent sign in
    // If the user's information is already in the app's cache,
    // they won't have to sign in again.
    string accessToken = string.Empty;
    try
    {
        var accounts = await PCA.GetAccountsAsync();
        if (accounts.Count() > 0)
        {
            var silentAuthResult = await PCA
                .AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                .ExecuteAsync();

            Debug.WriteLine("User already signed in.");
            Debug.WriteLine($"Access token: {silentAuthResult.AccessToken}");
            accessToken = silentAuthResult.AccessToken;
        }
    }
    catch (MsalUiRequiredException)
    {
        // This exception is thrown when an interactive sign-in is required.
        Debug.WriteLine("Silent token request failed, user needs to sign-in");
    }

    if (string.IsNullOrEmpty(accessToken))
    {
        // Prompt the user to sign-in
        var interactiveRequest = PCA
            .AcquireTokenInteractive(scopes);

        if (AuthUIParent != null)
        {
            interactiveRequest = interactiveRequest
                .WithParentActivityOrWindow(AuthUIParent);
        }

        var authResult = await interactiveRequest.ExecuteAsync();
        Debug.WriteLine($"Access Token: {authResult.AccessToken}");
    }

    // Initialize Graph client
    GraphClient = new GraphServiceClient(new DelegateAuthenticationProvider(
        async(requestMessage) =>
        {
            var accounts = await PCA
                .GetAccountsAsync();

            var result = await PCA
                .AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                .ExecuteAsync();

            requestMessage.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", result.AccessToken);
        }));

    await GetUserInfo();

    IsSignedIn = true;
}

it stops working on this line:

    var authResult = await interactiveRequest.ExecuteAsync();

Here is the source of my Entitlements.plist

enter image description here

Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
user979331
  • 11,039
  • 73
  • 223
  • 418

1 Answers1

0

There is a known issue with iOS 12 documented here:

Microsoft has released a security advisory to provide information about an incompatibility between iOS12 and some types of authentication. The incompatibility breaks social, WSFed, and OIDC logins. This advisory also provides guidance on what developers can do to remove current security restrictions added by ASP.NET to their applications to become compatible with iOS12.

I suspect the reason for the difference in behavior has to do with the iOS version on your device vs. the emulator.

The security advisory the docs link to includes some potential fixes:

If you are using ASP.NET Core Identity you disable the protection by configuring cookies with the following code

services.ConfigureExternalCookie(options =>
{
    // Other options
    options.Cookie.SameSite = SameSiteMode.None;
});
services.ConfigureApplicationCookie(options =>
{
    // Other options
    options.Cookie.SameSite = SameSiteMode.None;
});

If you are using cookie authentication without ASP.NET Core identity you can turn off the protection with the following code

services.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
    // Other options
    options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
})
Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63