I want to create a set of applications that uses Auzre B2C as SSO.
The application should allow the user to login, and if some expected data is missing, the user will be able to enter the missing data.
In a perfect scenario the solution should work with any login system so that I am able to switch to another login system (maybe self hosted) later.
These Applications share most of the user data but there are also specific data to each application.
An example of claims for my apps would be
App A: given name, sure name, email, display name
App B: given name, sure name, email, display name, billing address
App C: given name, sure name, email, display name, t-shirt size
App D: given name, sure name, email, display name, billing address, t-shirt size
My first thought was to store the user data inside the SSO solution and return the data in the claims after a successful login.
While in general just adding custom claims and store them in the AD is working after setting everything up on the Azure B2C managing page there are a few drawback I run into.
I created a default signinsignup user flow for each application, and did set the attributes that needs to be collected and returned as claims.
- Custom claims (even if set to non-optional) are only enforced on signup. Every user can sign in with the user flow even if non-optional claims are missing. I would have expected something like a login error or a redirect to the profile page to add the missing data. Is that even possible?
- When adding custom claims that way, I have to add the custom claims using the azure b2c managing webpage. Is there a way for an app itself to define custom claims and adding them to the user data? If I remember correctly a few years ago when implementing a SAML application I did define expected claims on the app level however I could not find something similar in the Blazor WebAssembly App Template in VS2022.
So I had 2 solutions in mind, but I do not know if they are possible.
-
Store date in AD
a. Custom claims can be stored and shared with different user flows
b. If a mandatory claim for the application is missing the users gets redirected to a page of the login system where they can enter the missing data.
c. Everything is handled by the login system. The application does only get the claims after a successful login (maybe does the redirect if claims are missing) and does not know anything about how the data is collected.
-
Store data in DB
a. Custom claims are stored in a database and got added to the token with an API Connector (https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-api-connector-token-enrichment?pivots=b2c-user-flow)
b. if claims are missing the application will let the user enter the missing data. Since this page is inside the app it will have to be implemented in each application.
c. Protect the data inside the database. At best only the user itself is able to decrypt the data. I was thinking about a generated password that will be returned with the claims that the app can use to decrypt the data. So as long as the app does not reveal the password the data is save, even from the admin.
Solution 2 seams more likely to be able to work and be a generic approach. There would also be the ultimate fallback option not to return these data inside the claims and instead access the database from each application to store and modify the data, only relying on the claims to provide the password needed for decryption. And at least I found some information for that approach.
On the other hand, solution 1 is close to a setup I imagined years ago where user login data is stored in an LDAP database and custom data is added by applications as needed. So that everything that is known about the user is stored in one secured place. And if I delete the user at this one place everything is gone without possible fragments of information still there.
What would be the best way to setup an environment like that?
2
Answers
The way to do this is to use custom policies.
On sign-in, you can check the optional claims and add a "profile edit" screen to the user journey to force them to be entered.
On the app. side, you can add custom (extension) attributes via the Graph API.
Personally, I would go for the sign-in approach.
I would recommend early planning of how you want to manage user attributes, since that is a key part of a portable and productive OAuth architecture.
USER ATTRIBUTE STORAGE
Store core identity attributes in the authorization server (AS). In many setups, other, business related user attributes can be stored in existing data sources. You should have choices about hor to manage and store user data.
POPULATING USER ATTRIBUTES
This can be done in a few ways, such as during self sign up or when migrating users to a new AS. This is often done using the built-in SCIM API provided by the AS. This behaviour should be portable across identity systems.
CLAIMS ISSUING
However the user attributes are stored, the AS should be able to reach out to data sources, read the values, then issue them to access tokens as claims. This enables you to lock down access tokens and ensure that APIs can authorize requests correctly.
FURTHER INFO
My blog post provides a summary of the main behaviours. Some AS providers may enable you to customize self sign up, but other options are possible. These include welcome or edit profile screens in applications that save attributes down to data sources using APIs.