skip to Main Content

I’ve set up Azure AD B2C with MSAL following this example. Users can log in with Facebook, I get a user object, all good.
Now I want to retrieve the attributes, like Country, City, etc. These are defined in the Azure AD B2C Attributes.

Do I need the Graph API for this? I’ve tried calling the graph.microsoft.com but I get token errors. I’ve read articles that I need to create an app registration, but when I use that Application ID instead of the one created in Azure AD B2C it throws an error that I need to use an App ID created under the B2C portal.

In the Application in B2C I can’t configure that I want access to Graph API.

We do have an C# API, where I could implement this logic probably. Is that the way to go? Ideally I want to do it straight from the client.

It’s all very confusing how this is working together. I’ve read most of the similar questions, but couldn’t find the same question.

3

Answers


  1. Chosen as BEST ANSWER

    The answers from @vibronet and @regnauld have helped a lot! I've configured the Sign In/Up policy to have the attributes in the claim. But the access token when using MSAL JS is encrypted. So, had to use this example to un-encrypt it:

    private setAuthenticated(accessToken: string) {
      // Update the UI.
      this.isAuthenticated = true;
      this.identity = Msal.Utils.extractIdToken(accessToken) as AuthIdentity;
      this.identity.displayName = this.identity.given_name + ' ' + this.identity.family_name;
      console.log(this.identity);
    }
    

    And then it worked! I can see all properties (address, display name, etc) in the console, without using the Graph API.


  2. At least for the attributes of the currently logged in user there is an approach that does not require Graph API. When you configure your sign_in and sign_up policies you can configure what claims are returned back via the token after a successful authentication.
    Note that this approach applies only for the currently logged in user. If you need information about other users you should use the graphAPI.

    Essentially in your application you could retrieve those claims/attributes from the current ClaimsPrincipal object.

    For example, here is a class, which I use in a current application and allows me to access all required information for the user. There is even a custom user attribute (phone_number):

    public class ApplicationUser : IApplicationUser
    {
        private readonly IHttpContextAccessor contextAccessor;
    
        public ApplicationUser(IHttpContextAccessor contextAccessor)
        {
            this.contextAccessor = contextAccessor;
        }
    
        public virtual bool IsAuthenticated => contextAccessor.HttpContext?.User?.Identity.IsAuthenticated ?? false;
    
        public string Id => GetAttribute(ClaimTypes.NameIdentifier);
        public string GivenName => GetAttribute(ClaimTypes.GivenName);
        public string Surname => GetAttribute(ClaimTypes.Surname);
        public string DisplayName => GetAttribute("name");
        public bool IsNewUser => GetBoolAttribute("newUser");
        public string Email => GetAttribute("emails");
        public string PhoneNumber => GetAttribute("extension_PhoneNumber");
    
        public bool IsCurrentUser(string userId)
        {
            return userId != null && Id != null && userId.Equals(Id, StringComparison.CurrentCultureIgnoreCase);
        }
    
        private string GetAttribute(string claim)
        {
            return IsAuthenticated ? contextAccessor.HttpContext.User.GetClaim(claim) : null;
        }
    
        public bool GetBoolAttribute(string claim)
        {
            bool output;
            bool.TryParse(GetAttribute(claim), out output);
            return output;
        }
    }
    
    public static class ClaimsPrincipalExtensions
    {
        public static string GetClaim(this ClaimsPrincipal principal, string claim)
        {
            if (principal == null)
            {
                throw new ArgumentNullException(nameof(principal));
            }
    
            if (string.IsNullOrWhiteSpace(claim))
            {
                throw new ArgumentNullException(nameof(claim));
            }
    
            return principal.FindFirst(claim)?.Value;
        }
    }
    

    The interface allows me to inject it wherever I need it:

    public interface IApplicationUser
    {
        string Id { get; }
        string GivenName { get; }
        string Surname { get; }
        string DisplayName { get; }
        bool IsNewUser { get; }
        string Email { get; }
        string PhoneNumber { get; }
    
        bool IsCurrentUser(string userId);
    }
    

    Edit: You could easily transfer this information to the client by creating a rest api endpoint and call it with ajax. Or pass it with data attributes in html.

    Login or Signup to reply.
  3. All the attributes you defined should appear in the idtoken, directly accessible from your client. Please refer to https://github.com/Azure-Samples/active-directory-b2c-xamarin-native/blob/master/UserDetailsClient/UserDetailsClient/MainPage.xaml.cs for one example of idtoken parsing logic directly on the client.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search