locked
xamarin forms azure b2c returning "" for access token RRS feed

  • Question

  • I have an a xamarin forms app that I am using the example at this link as a reference.

    https://docs.microsoft.com/en-us/samples/azure-samples/active-directory-b2c-xamarin-native/integrate-azure-ad-b2c-xamarin-forms/

    I have created my own azure tenant and configured as per the instructions.   I am able to authenticate through my azure b2c tenant through the OnLoginButtonClicked method shown below.   However, the result from the call to acquiretokeninteractive is returning and empty string "" for the accesstoken and what appears to be a valid token for the idtoken.  

    Looking for some thoughts on where my problem may be.  

    Thanks


     async void OnLoginButtonClicked(object sender, EventArgs e)
            {
                AuthenticationResult result;
                try
                {
                    result = await App.AuthenticationClient
                        .AcquireTokenInteractive(Constants.Scopes)
                        .WithPrompt(Prompt.SelectAccount)
                        
                        .WithParentActivityOrWindow(App.UIParent)
                        .ExecuteAsync();
                    Analytics.TrackEvent("accesstoken:" + result.AccessToken + " idtoken:" + result.IdToken);

                    //await Navigation.PushAsync(new LogoutPage(result));
                }
                catch (MsalException ex)
                {
                    if (ex.Message != null && ex.Message.Contains("AADB2C90118"))
                    {
                        result = await OnForgotPassword();
                        //await Navigation.PushAsync(new LogoutPage(result));
                    }
                    else if (ex.ErrorCode != "authentication_canceled")
                    {
                        await DisplayAlert("An error has occurred", "Exception message: " + ex.Message, "Dismiss");
                    }
                }
            }

    public App()
            {
                InitializeComponent();
                AuthenticationClient = PublicClientApplicationBuilder.Create(Constants.ClientId)
                    .WithIosKeychainSecurityGroup(Constants.IosKeychainSecurityGroups)
                    .WithB2CAuthority(Constants.AuthoritySignin)
                    .WithParentActivityOrWindow (()=> UIParent)
                    .WithRedirectUri($"msal{Constants.ClientId }://auth")
                    .Build();
                    
                MainPage = new AppShell();
            }

    {
        "id""e73c2f9a-d4ce-4c3b-bb03-0968ec96e507",
        "acceptMappedClaims"null,
        "accessTokenAcceptedVersion"2,
        "addIns": [],
        "allowPublicClient"true,
        "appId""49afe7f8-aadc-4545-bc1c-4b7478d7d591",
        "appRoles": [],
        "oauth2AllowUrlPathMatching"false,
        "createdDateTime""2019-11-10T21:40:00Z",
        "groupMembershipClaims""None",
        "identifierUris": [
            "https://MyNextbook.onmicrosoft.com/api"
        ],
        "informationalUrls": {
            "termsOfService"null,
            "support"null,
            "privacy"null,
            "marketing"null
        },
        "keyCredentials": [],
        "knownClientApplications": [],
        "logoUrl"null,
        "logoutUrl"null,
        "name""MNBApplication",
        "oauth2AllowIdTokenImplicitFlow"true,
        "oauth2AllowImplicitFlow"true,
        "oauth2Permissions": [
            {
                "adminConsentDescription""Allow the client application to access this app on behalf of the signed-in user.",
                "adminConsentDisplayName""Access this app on behalf of the signed-in user",
                "id""1c79b8c8-59d3-41ef-a5df-76a31c64b325",
                "isEnabled"true,
                "lang"null,
                "origin""Application",
                "type""User",
                "userConsentDescription"null,
                "userConsentDisplayName"null,
                "value""user_impersonation"
            }
        ],
        "oauth2RequirePostResponse"false,
        "optionalClaims": {
            "idToken": [
                {
                    "name""email",
                    "source"null,
                    "essential"false,
                    "additionalProperties": []
                },
                {
                    "name""family_name",
                    "source"null,
                    "essential"false,
                    "additionalProperties": []
                },
                {
                    "name""given_name",
                    "source"null,
                    "essential"false,
                    "additionalProperties": []
                }
            ],
            "accessToken": [
                {
                    "name""sid",
                    "source"null,
                    "essential"false,
                    "additionalProperties": []
                },
                {
                    "name""email",
                    "source"null,
                    "essential"false,
                    "additionalProperties": []
                },
                {
                    "name""family_name",
                    "source"null,
                    "essential"false,
                    "additionalProperties": []
                }
            ],
            "saml2Token": []
        },
        "orgRestrictions": [],
        "parentalControlSettings": {
            "countriesBlockedForMinors": [],
            "legalAgeGroupRule""Allow"
        },
        "passwordCredentials": [],
        "preAuthorizedApplications": [],
        "publisherDomain""MyNextbook.onmicrosoft.com",
        "replyUrlsWithType": [
            {
                "url""https://login.microsoftonline.com/common/oauth2/nativeclient",
                "type""InstalledClient"
            },
            {
                "url""https://login.live.com/oauth20_desktop.srf",
                "type""InstalledClient"
            },
            {
                "url""msal49afe7f8-aadc-4545-bc1c-4b7478d7d591://auth",
                "type""InstalledClient"
            },
            {
                "url""https://login.microsoftonline.com/tfp/oauth2/nativeclient",
                "type""InstalledClient"
            },
            {
                "url""https://MyNextbook.b2clogin.com/tfp/oauth2/nativeclient",
                "type""InstalledClient"
            },
            {
                "url""urn:ietf:wg:oauth:2.0:oob",
                "type""InstalledClient"
            },
            {
                "url""https://MyNextbook.b2clogin.com/MyNextbook.onmicrosoft.com/oauth2/authresp",
                "type""Web"
            }
        ],
        "requiredResourceAccess": [
            {
                "resourceAppId""00000003-0000-0000-c000-000000000000",
                "resourceAccess": [
                    {
                        "id""e1fe6dd8-ba31-4d61-89e7-88639da4683d",
                        "type""Scope"
                    }
                ]
            }
        ],
        "samlMetadataUrl"null,
        "signInUrl"null,
        "signInAudience""AzureADandPersonalMicrosoftAccount",
        "tags": [],
        "tokenEncryptionKeyId"null
    }


    Brady Brady@acm.org

    Friday, December 20, 2019 2:47 AM

All replies

  • Hi BradyG,

    We apologize for the delay in response. Based on this Github repo, if you're using  MSAL.NET 3.x you can use this  code to get a token for reading the user's profile with Microsoft Graph.

    string[] scopes = new string[] {"user.read"};
    var app = PublicClientApplicationBuilder.Create(clientId).Build();
    var accounts = await app.GetAccountsAsync();
    AuthenticationResult result;
    try
    {
     result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
                 .ExecuteAsync();
    }
    catch(MsalUiRequiredException)
    {
     result = await app.AcquireTokenInteractive(scopes)
                 .ExecuteAsync();
    }

    "

    AcquireTokenInteractive 

    has only one mandatory parameter scopes, which contains an enumeration of strings which define the scopes for which a token is required. If the token is for the Microsoft Graph, the required scopes can be found in api reference of each Microsoft graph API in the section named "Permissions"

    Hope that helps. Please let us know if you have further questions.

    Best,

    Grace


    Tuesday, January 7, 2020 12:17 AM
  • Thanks for the response.  I was able to get an access token back by providing 

    https://MyNextbook.onmicrosoft.com/api/user_impersonation

    as the scope.  If I provided just "user.read" in the scope I get an error message AADB2c90117: The scope user.read is not supported.

    When I try and use the access token from the scope user_impersonation to query microsoft graph.  On this call

     IGraphServiceUsersCollectionPage users = graphClient.Users.Request().GetAsync().Result;

    The call seems to never return and does not throw an exception. 

    Thanks for any insight you can provide.

    AuthenticationResult result;
                try
                {
                    string[] scopes2 = { "https://MyNextbook.onmicrosoft.com/api/user_impersonation openid offline_access",
                                                "https://MyNextbook.onmicrosoft.com/api/User.read"};
                    result = await App.AuthenticationClient
                        .AcquireTokenInteractive(scopes2)
                        .WithPrompt(Microsoft.Identity.Client.Prompt.SelectAccount)
                        
                        .WithParentActivityOrWindow(App.UIParent)
                        .ExecuteAsync();
                    System.Diagnostics.Debug.WriteLine("access token:" + result.AccessToken);
                    graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(
                   async (requestMessage) =>
                   {
                       // This is adding a bearer token to the httpclient used in the requests.
                       requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", result.AccessToken);
                   }));
    
                    IGraphServiceUsersCollectionPage users = graphClient.Users.Request().GetAsync().Result;
    
                    // I don't have many users, else I'd have to request the next page of results.
                    foreach (var user in users.CurrentPage)
                    {
                        Console.WriteLine("DisplayName: {0}", user.DisplayName);
                    }
    


    Brady Brady@acm.org

    Tuesday, January 7, 2020 3:40 AM
  • Hi Brady,

    What's the exception that you're getting? Also, what's the graph permission set for the user that you're using for impersonation?


    Thanks in advance, Ryan

    Wednesday, January 8, 2020 5:53 PM
  • Hi Brady,

    Do have any update for us on this issue?

    Thanks,

    Grace

    Thursday, January 23, 2020 11:59 PM