MicrosoftDocs / azure-docs

Open source documentation of Microsoft Azure
https://docs.microsoft.com/azure
Creative Commons Attribution 4.0 International
10.25k stars 21.41k forks source link

Can a B2C Access Token include app roles assigned to the user? #43316

Closed ahmadizm closed 4 years ago

ahmadizm commented 4 years ago

The access tokens issued by B2C do not seem to have the roles section. I do get them using active directory, but not through b2c. Although, it is possible to see them in the portal even in B2C directory. Is there a way to achieve this in the access token?

This is how I am getting a token: app = PublicClientApplicationBuilder.Create(Common.ClientId) .WithB2CAuthority(Common.AuthoritySignUpSignIn) .WithLogging(Log, LogLevel.Verbose, false) //PiiEnabled set to false .Build();

                    authResult = await app.AcquireTokenInteractive(Common.ApiScopes)
                                        .WithParentActivityOrWindowIfValid(_ParentWindowHandle)
                                        .WithPrompt(Prompt.SelectAccount)
                                        //.WithAccount(accounts.LastOrDefault())
                                        .ExecuteAsync();

Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Alberto-Vega commented 4 years ago

Hi @ahmadizm I'm sorry to hear that you are facing this issue. For some reason the issue is not linked to a document or tutorial. Could you please share the the URL of the documentation you were following? That way, we can pass your feedback to the appropriate content author.

We try to reserve this issues for documentation feedback. If you do not have feedback for a tutorial or document. Would you please open a question on StackOverflow or MSDN forums? There unlike here we have a developer community + engineering team that can help you.

ahmadizm commented 4 years ago

Thank you @Alberto-Vega-MSFT for following up. I was reading https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-tokens. In contrast, the active directory tokens explained at https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens do have a roles claim and I can get them using AD authentication. However, the B2C version does not seem to have that, and I was wondering if there is way to include those.

amanmcse commented 4 years ago

@ahmadizm Access token requested in application context (Application Token) include Roles claim and the token requested in user's context (User Token) includes SCP claim for the permissions exposed by your application.

The only case when you see Roles claim in User token is when the app role/roles are defined for the application in the App Manifest and the authenticating user is assigned with that role. Since B2C application's app manifest is not exposed for editing, you will not get Roles claim in the token issued by B2C directory.

Hope this answers your query.

ahmadizm commented 4 years ago

Thank you for your response. In B2C you can edit the app manifest: image image And you can have roles defined: image You can also assign those roles to users (admittedly, not through B2C portal), and B2C is able to see those apps and roles: image So given that B2C is able to see those apps and roles, I am wondering if I can find a way to see those roles in the token.

amanmcse commented 4 years ago

@ahmadizm Thanks for sharing the screenshots. I didn't notice that Application (Preview) is already added to the B2C blade.

I did the testing by making a token request at both oauth2 v1 and v2 endpoints after adding the app roles in the Manifest and confirmed that the Roles claim is not returned in case of B2C. I have shared the calls below with required parameters that I made to request for a token.

Having said that, I couldn't think of a scenario why you want to pass the roles claim for a consumer account using App roles defined in the app manifest. As B2C is used for consumer identities where they sign-up to create the accounts, it would not be feasible for the Administrator to add their accounts to the app assigning the roles to their identities. For this purpose we suggest to use custom claims in B2C where the consumer selects required role during the signup process which is returned in the token as well. Please refer to https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-rest-api-step-custom for more details.

In case, if you are not dealing with consumer identities, I would suggest you to go with standard Azure AD rather than Azure AD B2C.

Hope I have covered all aspects of your question. Feel free to tag me in your reply if you have any further questions.

OAuth v1 endpoint:

POST https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/token?p=b2c_1A_signup_signin
grant_type:authorization_code
client_id:2c9296bb-xxxx-xxxx-xxxx-30d38790dea1
resource:2c9296bb-xxxx-xxxx-xxxx-30d38790dea1
code:eyJraWQiOiI1M...
redirect_uri:https://b2c.amansi.msftonlinerepro.com
scope:openid

OAuth v2 endpoint:

POST https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1A_signup_signin
grant_type:authorization_code
client_id:2c9296bb-xxxx-xxxx-xxxx-30d38790dea1
code:eyJraWQiOiI1...
redirect_uri:https://b2c.amansi.msftonlinerepro.com
client_secret:OWxxxxxxxxxxxxco6UCf
scope:https://amsin.onmicrosoft.com/api/read
ahmadizm commented 4 years ago

@amanmcse, this is great information, thank you. I kind of came to the same conclusion that B2C may not be the right place to assign and retrieve application roles. Now that I have your confirmation, I will resort to regular AD for special app roles that employees should have. Thanks again.

DibyodyutiMondal commented 4 years ago

I feel there may be a use case where it'd be best to have appRoles even with B2C.

What if I had an SPA+API architecture where both the SPA and API were using RBAC?

If it was a customer, then they can read products. But an administrator can create, read, update and delete products.

Both these actions can be performed from the same SPA, depending on who is logging in, and the 'roles' claim they have. Admins would need to federate through Azure AD anyway.

This model would eliminate the need to develop multiple apps, one for the management, one for the customer, and one for the delivery guys.

Also, imagine another scenario, where I'm a college, and would like to allow the students to see their marks online, but instead of making them remember another password, the students and teachers can log in through their social accounts, as well as leave the option of using their roll no. or employee id. There are 2 distinct roles here. One to publish the marks, one to read them.

Using custom claims to get roles is the best way to achieve this right now. But I feel getting the appRoles along with the token would be a true in-built solution.

Also, ideally, users should never be able to change their roles. That's something that the custom policy will either set by default during the sign-up process, for example "Customer" role. And if it's a special user, then the admin will be using the graph API to create the user anyway, for example, "DeliveryBoy" role. This role won't even have a signUp policy, or alternatively, the role will be set by the management, after the application has been approved. Another alternative is that the delivery boy will be required to federate through Azure AD.

Either way, I feel appRoles are very useful even in B2C scenarios and not just within the organisation.

lfecci commented 4 years ago

both the SPA and API were using RBAC?

I have this exact requirement.

harry12345678910 commented 4 years ago

For this purpose we suggest to use custom claims in B2C where the consumer selects required role during the signup process which is returned in the token as well.

Really?? The consumers should be able to select the role "admin"??? We have a scenario, where we have internal application administrators, and external consumers using the application. Additionally we have on consumer side "special" site admins, that need to be created by us. They have the privilege to add additional users for their site

svdHero commented 2 years ago

@harry12345678910 @DibyodyutiMondal @lfecci I have the same use case in my enterprise application. How did you people solve this in your case?

And is there any feature request for adding app roles to B2C?

DibyodyutiMondal commented 2 years ago

Unfortunately, I moved away from azure for public-facing websites, just because of this. :(

But I do remember that I made an extremely, extremely convoluted custom policy for this. So it is possible, but fair warning: it is painful to write. It felt like using xml to write full-blown functions (complete with variable declarations and assignments - frankly, I would even say it was on par with server side code, but in XML!).

To start, the 3 places you want to look at are

  1. the B2C policy file documentation,
  2. the B2C custom policy sample github repo, and
  3. the vs code b2c policy editor extension by Microsoft After you have read these thoroughly ( especially the samples), you can truly start.

Next, you have to start looking at the policy file as describing a set of linear instructions, and not just a normal xml document. It's like using XML to write instructions that another machine is going to read and use to write/choose the code that actually handles the user flow. (Don't ask me why this is)

For example, I ended up using the preconditions and validation clauses as a kind of if/else statements. Claims Transformations are your friends too. I have forgotten the details, but the documentation on the custom policy file was actually pretty informative. However, they don't tell you exactly how to do things - you have to figure out for yourselves. It's relative easily to grasp, but it's extremely convoluted, lengthy, and to me at least, over-engineered.

Roughly, the steps you need to do were to add extension_role claim to the list of claims, in the base policy file. This tells B2C that you are create a custom claim called role . In the policy files, refer to it as extension_roles but get it as role in the token. (Again, don't ask me why) Then in the Technical Profile that you create for Azure AD, replace the roles you created with ones you get from Azure AD (using a claims transformation) (Or add them instead of replacing - it's up to you).

Otherwise, stick as close to the samples as you can. Even so, I clearly remember breaking up the Technical Profiles into the smallest possible reusable units, for example, creating a base profile AzureADBase, and then extending that in AzureADEmail and AzureADPhone. It helps you with the cacophony.

This was quite a while ago, so I know things may be very different now, and I apologize in advance if this comment did not really help at all. I will try to see if the policy files still exists somewhere, but it's unlikely.

Even after all of this, I found that I could not style the user flow pages as much as I would have wished. It's possible, but it wasn't enough for me. Hopefully, after .NET 6 and C#10, Microsoft allows us to write our policy flows as small code files, with only a subset of the C# APIs enabled or something. Or at the very least, let us write the policies in json instead of XML!

svdHero commented 2 years ago

@DibyodyutiMondal Thank you for your detailled answer. I am very grateful for it. May I ask what you are using for public-facing websites instead of Azure?

DibyodyutiMondal commented 2 years ago

I used firebase hosting with firebase authentication. Setting up custom claims is super easy for most use cases, but RBAC in my opinion is always an advanced scenario, so fair warning: it is not as easy as firebase advertises. However, in terms of sign up flow, it's much much simpler than anything I've ever done before in C#.

The easiest I've had it in C# was to make my own custom JWTs from a self-made .net core API from user data stored in SQL Server. (I imagine these days you could use cosmos DB free tier if your app is small)

With firebase, you have to do roughly the same thing, but it's so much easier.

  1. Whenever, a user signs in, they immediately get a jwt token. However this token is a token created by firebase, so it has no extra claims nothing. But, firebase does include a newUser metadata in such tokens

  2. I have a cloud function (a serverless function) which is automatically triggered whenever a new user signs up. This function adds the necessary custom claims, as simple as adding properties to an object. I can make http calls to anywhere in the where to get back the information I need.

  3. On the client side, since I have a token which does not include the properties I'm expecting, I can tell that I'm dealing with a completely uninitialised user. So I show an 'new account setup' screen and wait while polling every few seconds for a token that does include the roles claims, populated by my cloud function.

  4. From here it's pretty much business as usual.

Plus, to me, typescript is like C# type-safety + javascript simplicity.

I know I digress, and this is an issue about Azure AD B2C. But I still went ahead in the hopes that Microsoft employees who read can view the difference that in development experience that I have had, and I'm sure many people, have had. And I hope they realise that the difference in complexity for such a basic and core requirement such as authentication, at least in Azure B2C is driving away even the most loyal customers to other platforms.

DannyBoyIT commented 1 year ago

Is this still the case? Seems like very basic functionality to be missing from Azure B2C. I found some work arrounds online but I don't feel they are worth the time when this should be provided out of the box. This might be a show stopper for us for recommending our customers to use Azure B2C.

svdHero commented 1 year ago

@DannyBoyIT yes, I am afraid so. We ended up implementing a custom userflow/policy that uses an Azure Function which contacts AD and fills the token with custom claims. It's far too complex for such a simple feature. Tonnes of XML code. I am just glad that our external Azure consultant deals with this specific part of the application.

As much as I love Azure and MSAL in general, as much do I hate B2C for being that weird MacGyver DIY mix that desperately tries to keep everything together with sticks and chewing gum. The UX for developers is awful.

AndrewCraswell commented 1 year ago

I also moved away from Azure AD B2C because of lack of basic RBAC. It's a pretty fundamental aspect of any authentication system, but it's by far the most convoluted system out of any other cloud provider.

I settled with Auth0 for now, and had everything up and running in minutes.

oshihirii commented 1 year ago

The information and considerations in this thread are excellent. I am a relative newbie to Azure and B2C authentication but intuitively felt there was something that was too complex in the custom policy setup and the methods available for returning roles and groups in claims. The more advanced users here have articulated their experiences based on significant study and practice and it is reassuring to hear they have arrived at similar conclusions. (I currently have to keep using B2C so will keep searching to find the simplest way to return roles and groups in id_token/claims).