I want to query Azure AD Graph API to retrieve the groups claim for the logged in user from a registered Azure B2C app. The app I'm calling from is an Angular 5 SPA.
After experimenting with Azure Active Directory and adal-angular4, I was successful retrieving a user's custom roles claim. To do this, I registered an Azure AD app, set required permission scopes, added custom roles to the application's manifest, added the user to the application, and set the custom role for the user. Then, I used my new registered app's application id and tenant for the adal-angular4 config. When I query the endpoint I get the token which contains the roles claim. It works well. When I change the role it shows in the token.
This roles claim would be enough for me but it requires two logins, one for my B2C app, and one for my other registered app. I don’t think I can use the same token for both.
In order to have only one login, I want to query Azure B2C directly. I’ve heard it doesn't offer the ability to query the user's roles like Azure Active Directory, and have been directed to use user groups. I also have seen documentation and have been told that I need to use Azure Graph API because Microsoft Graph has not implemented the ability to query this info yet.
I tried to follow a similar path for B2C that I used with AAD. I created a group and added a user to the group. I have tried to access my B2C app's information with the Azure Graph API endpoint https://graph.windows.net/myorganization/users?api-version=1.6 using MSAL.js but I get the error "code": "Authentication_MissingOrMalformed". I verified that a token is retrieved by MSAL and is being added to the request. When I change the url to one that is invalid, I get the same error. I have searched and found questions with the same problem here, here, but none are answered
How do I fix this error?
Is it necessary to have a local admin account?
Are there any special Scopes I need to set on my B2C app to grant authorization for my queries? If there are, what specifically are they? I have tried to swapping different values for the scopes into the MSAL config and haven't found anything that works.
Does this app need to be multi tenant?
I have found resources on access tokens and scopes but I'm using Angular 5 / typescript and don't have the Azure AD Graph Client Library that's available in .NET. I haven't been able to make use of either resource.
Azure AD B2C issues tokens using the Azure AD v2.0 endpoint:
The Azure AD Graph API requires tokens that are issued using the Azure AD v1.0 endpoint:
For a single-page application to access to the Azure AD Graph API, you must bridge them using a proxy API (I will call this the User API), as follows.
At design-time:
At runtime:
I wanted to write this to help others who might be stuck in the same rut I was in trying to find a basic direction / understanding. I essentially went with the workflow that @Chris Pradget described. My initial perception of the problem was wrong though and I’ll clarify where my error was and give a little context.
My initial goal was to bring a user’s roles and / or groups claims when a user logs in to my Azure / Angular App. Azure doesn’t have an easy way to do this when you are logging in with Azure B2C for policies. (In some regards it seems that Firebase makes this easy).
After a bunch of research and not really comprehending the big picture I saw what seemed to be conflicting information which took some time to sort through. Eventually I found the information I was looking for which was that I couldn’t have only one login.
(Just a heads up, I refer to my classic Azure AD registered app as an 'app registration' just to draw a distinction from the code implementation and the configuration set in Azure's Portal)
It took alot of experimentation, but i came up with something that seems to work. I essentially retrieve 3 tokens, 2 in Angular using MSAL.js and one in .NET using ADAL for Microsoft Graph. One in Angular is for the initial login (MSAL Client's loginRedirect call) to retrieve the id_token and the other I retrieved using that token along with the aquireTokenSlient function to retrieve the access_token. I sent that to my .NET Core backend where I used the users id from the incoming token as resource id in a request to Microsoft Graph to get my groups claim and then I crafted my own JWT token with the claims to send back to Angular for my route guards.
Things of note in my research:
Azure AD Graph vs Microsoft Graph to pull user groups: There’s conflicting information about which to use, some say Microsoft Graph because Azure Graph is being deprecated, but others say Azure Graph because MS Graph doesn’t cover all of the bases yet. After experimenting, I found that I was able to pull a user’s groups out of MS Graph. Given that and the fact that MS Graph is newer, I went with MS Graph. For experimentation with the graphs I used both Azure Graph explorer and MS Graph Explorer.
It took me awhile to successfully query the Microsoft Graph, but when I did was through MS Graph Explorer as stated above. The main problem I first encountered was when I queried my app with my own account. Only some queries worked and even those brought back very limited info. It wasn’t until I re-read this article about the Azure AD Graph API did I notice that in order to query the Graphs, you need to use a user id that is local to your tenant’s domain and is an admin. When I created and used my tenant’s admin (from that domain), all of the queries worked. So as far as my questions above are concerned:
1) How do I fix this ["code": "Authentication_MissingOrMalformed"] error? Use a local admin account
2) Is it necessary to have a local admin account? Yes
3) Are there any special Scopes I need to set on my B2C app to grant authorization for my queries? If there are, what specifically are they? To query the MS Graph in the ways you want with ADAL use Directory.Read Access
4) Does this app need to be multi tenant? No
Additionally In my research I found that instead of using B2C Groups, you can use Azure AD Roles. Specifically, Application Roles can be added to a Classic Azure AD app manifest in the Azure Portal. It was a different route that looked promising for me. I found this article describing how to edit the manifest to add the Application Roles. First you add roles to the manifest, next you assign users to roles in the Azure Portal, then you query the user information (from Angular) using the ADAL.js library. When you login using the library, the Application Roles are brought down on the token acquired. This of course doesn't use the B2C policies. Also this might go without saying, but when you login, neither the B2C id_token or access_token can be used to acquire the Classic Azure AD credentials/token. I tried to think of other ways to accomplish what I wanted. Given that the 2 registrations are in the same tenant I thought I could use single sign on to log into one and remain logged in for the other. I didn’t get very far. Another method that I considered was using custom policies to retrieve the data from my Azure AD classic app but didn’t get far with that either.
Also when @Chris Padgett mentioned creating a "user api", I misinterpreted it. By "user api" I thought he meant my classic Azure Ad app registration, which was set up in Azure Portal, houses my user info, and acts as an api to retrieve my token. I thought I first needed to obtain an access token from B2C in Angular and then use that token (still in Angular) to access my Azure AD classic registration. From there I would be able to pull down my users' information including the Application Roles (made accessible from editing the manifest). This wouldn't have worked because as I've stated above I wanted to do this with one login and you can't use a B2C token in a Classic Azure AD app. Even if it did work, it would have required setting roles for users in my classic Azure AD app registration outside of my B2C app which I didn't want to do. Having one app registration for the policies and another to manage users' roles isn't very elegant. Also getting it to work would require 2 logins one for B2C and one for Classic Azure AD. In this approach, it feels like these 2 apps are separate and I don't want to divvy up concerns across 2 platforms. So, in the end, the scenario of logging in with B2C in Angular and then hitting the server to pull the user groups with MS Graph is a better one. The backend app only needs to log in once independent of users accessing it, which means users don't need to log in twice. Also it consolidates my information to my B2C app registration.
I'm think Azure might eventually provide the groups and / or roles on their id_tokens in the future, but I thought this info might be helpful to people in the meantime. In addition here are links to other related questions I asked that helped guide me my research:
Learning that I needed to use MSAL.js over ADAL.js in order to use B2C Policies.
A similar question I asked about querying MS Graph and getting a limited response